+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ostree.h"
-#include "otutil.h"
-
-enum {
- PROP_0,
-
- PROP_REPO,
- PROP_PATH
-};
-
-G_DEFINE_TYPE (OstreeCheckout, ostree_checkout, G_TYPE_OBJECT)
-
-#define GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), OSTREE_TYPE_CHECKOUT, OstreeCheckoutPrivate))
-
-typedef struct _OstreeCheckoutPrivate OstreeCheckoutPrivate;
-
-struct _OstreeCheckoutPrivate {
- OstreeRepo *repo;
- char *path;
-};
-
-static void
-ostree_checkout_finalize (GObject *object)
-{
- OstreeCheckout *self = OSTREE_CHECKOUT (object);
- OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
-
- g_free (priv->path);
- g_clear_object (&priv->repo);
-
- G_OBJECT_CLASS (ostree_checkout_parent_class)->finalize (object);
-}
-
-static void
-ostree_checkout_set_property(GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- OstreeCheckout *self = OSTREE_CHECKOUT (object);
- OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
-
- switch (prop_id)
- {
- case PROP_PATH:
- priv->path = g_value_dup_string (value);
- break;
- case PROP_REPO:
- priv->repo = g_value_dup_object (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-ostree_checkout_get_property(GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- OstreeCheckout *self = OSTREE_CHECKOUT (object);
- OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
-
- switch (prop_id)
- {
- case PROP_PATH:
- g_value_set_string (value, priv->path);
- break;
- case PROP_REPO:
- g_value_set_object (value, priv->repo);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GObject *
-ostree_checkout_constructor (GType gtype,
- guint n_properties,
- GObjectConstructParam *properties)
-{
- GObject *object;
- GObjectClass *parent_class;
- OstreeCheckoutPrivate *priv;
-
- parent_class = G_OBJECT_CLASS (ostree_checkout_parent_class);
- object = parent_class->constructor (gtype, n_properties, properties);
-
- priv = GET_PRIVATE (object);
-
- g_assert (priv->path != NULL);
-
- return object;
-}
-
-static void
-ostree_checkout_class_init (OstreeCheckoutClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (OstreeCheckoutPrivate));
-
- object_class->constructor = ostree_checkout_constructor;
- object_class->get_property = ostree_checkout_get_property;
- object_class->set_property = ostree_checkout_set_property;
- object_class->finalize = ostree_checkout_finalize;
-
- g_object_class_install_property (object_class,
- PROP_PATH,
- g_param_spec_string ("path", "", "",
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class,
- PROP_REPO,
- g_param_spec_object ("repo", "", "",
- OSTREE_TYPE_REPO,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void
-ostree_checkout_init (OstreeCheckout *self)
-{
-}
-
-OstreeCheckout*
-ostree_checkout_new (OstreeRepo *repo,
- const char *path)
-{
- return g_object_new (OSTREE_TYPE_CHECKOUT, "repo", repo, "path", path, NULL);
-}
-
-static gboolean
-executable_exists_in_checkout (const char *path,
- const char *executable)
-{
- int i;
- const char *subdirs[] = {"bin", "sbin", "usr/bin", "usr/sbin"};
-
- for (i = 0; i < G_N_ELEMENTS (subdirs); i++)
- {
- char *possible_path = g_build_filename (path, subdirs[i], executable, NULL);
- gboolean exists;
-
- exists = g_file_test (possible_path, G_FILE_TEST_EXISTS);
- g_free (possible_path);
-
- if (exists)
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-run_trigger (OstreeCheckout *self,
- GFile *trigger,
- gboolean requires_chroot,
- GError **error)
-{
- OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- char *path = NULL;
- char *temp_path = NULL;
- char *rel_temp_path = NULL;
- GFile *temp_copy = NULL;
- char *basename = NULL;
- GPtrArray *args = NULL;
- int estatus;
-
- path = g_file_get_path (trigger);
- basename = g_path_get_basename (path);
-
- args = g_ptr_array_new ();
-
- if (requires_chroot)
- {
- temp_path = g_build_filename (priv->path, basename, NULL);
- rel_temp_path = g_strconcat ("./", basename, NULL);
- temp_copy = ot_util_new_file_for_path (temp_path);
-
- if (!g_file_copy (trigger, temp_copy, 0, NULL, NULL, NULL, error))
- goto out;
-
- g_ptr_array_add (args, "chroot");
- g_ptr_array_add (args, ".");
- g_ptr_array_add (args, rel_temp_path);
- g_ptr_array_add (args, NULL);
- }
- else
- {
- g_ptr_array_add (args, path);
- g_ptr_array_add (args, NULL);
- }
-
- g_print ("Running trigger: %s\n", path);
- if (!g_spawn_sync (priv->path,
- (char**)args->pdata,
- NULL,
- G_SPAWN_SEARCH_PATH,
- NULL, NULL, NULL, NULL,
- &estatus,
- error))
- {
- g_prefix_error (error, "Failed to run trigger %s: ", basename);
- goto out;
- }
-
- ret = TRUE;
- out:
- if (requires_chroot && temp_path)
- (void)unlink (temp_path);
-
- g_free (path);
- g_free (basename);
- g_free (temp_path);
- g_free (rel_temp_path);
- g_clear_object (&temp_copy);
- if (args)
- g_ptr_array_free (args, TRUE);
- return ret;
-}
-
-static gboolean
-check_trigger (OstreeCheckout *self,
- GFile *trigger,
- GError **error)
-{
- OstreeCheckoutPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- GInputStream *instream = NULL;
- GDataInputStream *datain = NULL;
- GError *temp_error = NULL;
- char *line;
- gsize len;
- gboolean requires_chroot = TRUE;
- gboolean matches = FALSE;
-
- instream = (GInputStream*)g_file_read (trigger, NULL, error);
- if (!instream)
- goto out;
- datain = g_data_input_stream_new (instream);
-
- while ((line = g_data_input_stream_read_line (datain, &len, NULL, &temp_error)) != NULL)
- {
- if (g_str_has_prefix (line, "# IfExecutable: "))
- {
- char *executable = g_strdup (line + strlen ("# IfExecutable: "));
- g_strchomp (executable);
- matches = executable_exists_in_checkout (priv->path, executable);
- g_free (executable);
- }
-
- g_free (line);
- }
- if (line == NULL && temp_error != NULL)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- if (matches)
- {
- if (!run_trigger (self, trigger, requires_chroot, error))
- goto out;
- }
-
- ret = TRUE;
- out:
- g_clear_object (&instream);
- g_clear_object (&datain);
- return ret;
-}
-
-gboolean
-ostree_checkout_run_triggers (OstreeCheckout *self,
- GError **error)
-{
- gboolean ret = FALSE;
- GError *temp_error = NULL;
- char *triggerdir_path = NULL;
- GFile *triggerdir = NULL;
- GFileInfo *file_info = NULL;
- GFileEnumerator *enumerator = NULL;
-
- triggerdir_path = g_build_filename (LIBEXECDIR, "ostree", "triggers.d", NULL);
- triggerdir = ot_util_new_file_for_path (triggerdir_path);
-
- enumerator = g_file_enumerate_children (triggerdir, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL,
- error);
- if (!enumerator)
- goto out;
-
- while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
- {
- const char *name;
- guint32 type;
- char *child_path = NULL;
- GFile *child = NULL;
- gboolean success;
-
- name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
- type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
-
- if (type == G_FILE_TYPE_REGULAR && g_str_has_suffix (name, ".trigger"))
- {
- child_path = g_build_filename (triggerdir_path, name, NULL);
- child = ot_util_new_file_for_path (child_path);
-
- success = check_trigger (self, child, error);
- }
- else
- success = TRUE;
-
- g_object_unref (file_info);
- g_free (child_path);
- g_clear_object (&child);
- if (!success)
- goto out;
- }
- if (file_info == NULL && temp_error != NULL)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
-
- ret = TRUE;
- out:
- g_free (triggerdir_path);
- g_clear_object (&triggerdir);
- g_clear_object (&enumerator);
- return ret;
-}
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef _OSTREE_CHECKOUT
-#define _OSTREE_CHECKOUT
-
-#include <ostree-repo.h>
-
-G_BEGIN_DECLS
-
-#define OSTREE_TYPE_CHECKOUT ostree_checkout_get_type()
-#define OSTREE_CHECKOUT(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckout))
-#define OSTREE_CHECKOUT_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
-#define OSTREE_IS_CHECKOUT(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_CHECKOUT))
-#define OSTREE_IS_CHECKOUT_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_CHECKOUT))
-#define OSTREE_CHECKOUT_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_CHECKOUT, OstreeCheckoutClass))
-
-typedef struct {
- GObject parent;
-} OstreeCheckout;
-
-typedef struct {
- GObjectClass parent_class;
-} OstreeCheckoutClass;
-
-GType ostree_checkout_get_type (void);
-
-OstreeCheckout* ostree_checkout_new (OstreeRepo *repo,
- const char *path);
-
-gboolean ostree_checkout_run_triggers (OstreeCheckout *checkout,
- GError **error);
-
-G_END_DECLS
-
-#endif /* _OSTREE_CHECKOUT */
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ostree.h"
-#include "otutil.h"
-
-#include <sys/types.h>
-#include <attr/xattr.h>
-
-gboolean
-ostree_validate_checksum_string (const char *sha256,
- GError **error)
-{
- if (strlen (sha256) != 64)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid rev '%s'", sha256);
- return FALSE;
- }
- return TRUE;
-}
-
-
-void
-ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode)
-{
- guint32 perms = (mode & ~S_IFMT);
- g_checksum_update (checksum, (guint8*) &uid, 4);
- g_checksum_update (checksum, (guint8*) &gid, 4);
- g_checksum_update (checksum, (guint8*) &perms, 4);
-}
-
-static char *
-canonicalize_xattrs (char *xattr_string, size_t len)
-{
- char *p;
- GSList *xattrs = NULL;
- GSList *iter;
- GString *result;
-
- result = g_string_new (0);
-
- p = xattr_string;
- while (p < xattr_string+len)
- {
- xattrs = g_slist_prepend (xattrs, p);
- p += strlen (p) + 1;
- }
-
- xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp);
- for (iter = xattrs; iter; iter = iter->next)
- g_string_append (result, iter->data);
-
- g_slist_free (xattrs);
- return g_string_free (result, FALSE);
-}
-
-static gboolean
-read_xattr_name_array (const char *path,
- const char *xattrs,
- size_t len,
- GVariantBuilder *builder,
- GError **error)
-{
- gboolean ret = FALSE;
- const char *p;
-
- p = xattrs;
- while (p < xattrs+len)
- {
- ssize_t bytes_read;
- char *buf;
-
- bytes_read = lgetxattr (path, p, NULL, 0);
- if (bytes_read < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- if (bytes_read == 0)
- continue;
-
- buf = g_malloc (bytes_read);
- if (lgetxattr (path, p, buf, bytes_read) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- g_free (buf);
- goto out;
- }
-
- g_variant_builder_add (builder, "(@ay@ay)",
- g_variant_new_bytestring (p),
- g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
- buf, bytes_read, FALSE, g_free, buf));
-
- p = p + strlen (p) + 1;
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-GVariant *
-ostree_get_xattrs_for_path (const char *path,
- GError **error)
-{
- GVariant *ret = NULL;
- GVariantBuilder builder;
- char *xattr_names = NULL;
- char *xattr_names_canonical = NULL;
- ssize_t bytes_read;
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
-
- bytes_read = llistxattr (path, NULL, 0);
-
- if (bytes_read < 0)
- {
- if (errno != ENOTSUP)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else if (bytes_read > 0)
- {
- xattr_names = g_malloc (bytes_read);
- if (llistxattr (path, xattr_names, bytes_read) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
-
- if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &builder, error))
- goto out;
- }
-
- ret = g_variant_builder_end (&builder);
- g_variant_ref_sink (ret);
- out:
- if (!ret)
- g_variant_builder_clear (&builder);
- g_free (xattr_names);
- g_free (xattr_names_canonical);
- return ret;
-}
-
-gboolean
-ostree_stat_and_checksum_file (int dir_fd, const char *path,
- OstreeObjectType objtype,
- GChecksum **out_checksum,
- struct stat *out_stbuf,
- GError **error)
-{
- GChecksum *content_sha256 = NULL;
- GChecksum *content_and_meta_sha256 = NULL;
- char *stat_string = NULL;
- ssize_t bytes_read;
- GVariant *xattrs = NULL;
- int fd = -1;
- DIR *temp_dir = NULL;
- char *basename = NULL;
- gboolean ret = FALSE;
- char *symlink_target = NULL;
- char *device_id = NULL;
- struct stat stbuf;
-
- basename = g_path_get_basename (path);
-
- if (dir_fd == -1)
- {
- char *dirname = g_path_get_dirname (path);
- temp_dir = opendir (dirname);
- if (temp_dir == NULL)
- {
- ot_util_set_error_from_errno (error, errno);
- g_free (dirname);
- }
- g_free (dirname);
- dir_fd = dirfd (temp_dir);
- }
-
- if (fstatat (dir_fd, basename, &stbuf, AT_SYMLINK_NOFOLLOW) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- if (S_ISREG(stbuf.st_mode))
- {
- fd = ot_util_open_file_read_at (dir_fd, basename, error);
- if (fd < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
-
- if (objtype == OSTREE_OBJECT_TYPE_FILE)
- {
- xattrs = ostree_get_xattrs_for_path (path, error);
- if (!xattrs)
- goto out;
- }
-
- content_sha256 = g_checksum_new (G_CHECKSUM_SHA256);
-
- if (S_ISREG(stbuf.st_mode))
- {
- guint8 buf[8192];
-
- while ((bytes_read = read (fd, buf, sizeof (buf))) > 0)
- g_checksum_update (content_sha256, buf, bytes_read);
- if (bytes_read < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else if (S_ISLNK(stbuf.st_mode))
- {
- symlink_target = g_malloc (PATH_MAX);
-
- g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
-
- bytes_read = readlinkat (dir_fd, basename, symlink_target, PATH_MAX);
- if (bytes_read < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- g_checksum_update (content_sha256, (guint8*)symlink_target, bytes_read);
- }
- else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode))
- {
- g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
- device_id = g_strdup_printf ("%u", (guint)stbuf.st_rdev);
- g_checksum_update (content_sha256, (guint8*)device_id, strlen (device_id));
- }
- else if (S_ISFIFO(stbuf.st_mode))
- {
- g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
- }
- else
- {
- g_set_error (error, G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "Unsupported file '%s' (must be regular, symbolic link, fifo, or character/block device)",
- path);
- goto out;
- }
-
- content_and_meta_sha256 = g_checksum_copy (content_sha256);
-
- if (objtype == OSTREE_OBJECT_TYPE_FILE)
- {
- ostree_checksum_update_stat (content_and_meta_sha256, stbuf.st_uid,
- stbuf.st_gid, stbuf.st_mode);
- g_checksum_update (content_and_meta_sha256, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
- }
-
- *out_stbuf = stbuf;
- *out_checksum = content_and_meta_sha256;
- ret = TRUE;
- out:
- if (fd >= 0)
- close (fd);
- if (temp_dir != NULL)
- closedir (temp_dir);
- g_free (symlink_target);
- g_free (basename);
- g_free (stat_string);
- if (xattrs)
- g_variant_unref (xattrs);
- if (content_sha256)
- g_checksum_free (content_sha256);
- return ret;
-}
-
-gboolean
-ostree_set_xattrs (const char *path, GVariant *xattrs, GCancellable *cancellable, GError **error)
-{
- gboolean ret = FALSE;
- int i, n;
-
- n = g_variant_n_children (xattrs);
- for (i = 0; i < n; i++)
- {
- const guint8* name;
- GVariant *value;
- const guint8* value_data;
- gsize value_len;
- gboolean loop_err;
-
- g_variant_get_child (xattrs, i, "(^&ay@ay)",
- &name, &value);
- value_data = g_variant_get_fixed_array (value, &value_len, 1);
-
- loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, XATTR_REPLACE) < 0;
-
- g_variant_unref (value);
- if (loop_err)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-gboolean
-ostree_parse_metadata_file (const char *path,
- OstreeSerializedVariantType *out_type,
- GVariant **out_variant,
- GError **error)
-{
- GFile *pathf = NULL;
- gboolean ret = FALSE;
- GVariant *ret_variant = NULL;
- GVariant *container = NULL;
- guint32 ret_type;
-
- pathf = ot_util_new_file_for_path (path);
- if (!ot_util_variant_map (pathf, G_VARIANT_TYPE (OSTREE_SERIALIZED_VARIANT_FORMAT),
- &container, error))
- goto out;
-
- g_variant_get (container, "(uv)",
- &ret_type, &ret_variant);
- ret_type = GUINT32_FROM_BE (ret_type);
- if (ret_type <= 0 || ret_type > OSTREE_SERIALIZED_VARIANT_LAST)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted metadata object '%s'; invalid type %d", path, ret_type);
- goto out;
- }
-
- ret = TRUE;
- *out_type = ret_type;
- *out_variant = ot_util_variant_take_ref (ret_variant);
- ret_variant = NULL;
- out:
- if (ret_variant)
- g_variant_unref (ret_variant);
- if (container != NULL)
- g_variant_unref (container);
- g_clear_object (&pathf);
- return ret;
-}
-
-char *
-ostree_get_relative_object_path (const char *checksum,
- OstreeObjectType type,
- gboolean archive)
-{
- GString *path;
- const char *type_string;
-
- g_assert (strlen (checksum) == 64);
-
- path = g_string_new ("objects/");
-
- g_string_append_len (path, checksum, 2);
- g_string_append_c (path, '/');
- g_string_append (path, checksum + 2);
- switch (type)
- {
- case OSTREE_OBJECT_TYPE_FILE:
- if (archive)
- type_string = ".packfile";
- else
- type_string = ".file";
- break;
- case OSTREE_OBJECT_TYPE_META:
- type_string = ".meta";
- break;
- default:
- g_assert_not_reached ();
- }
- g_string_append (path, type_string);
- return g_string_free (path, FALSE);
-}
-
-gboolean
-ostree_pack_object (GOutputStream *output,
- GFile *file,
- OstreeObjectType objtype,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- char *path = NULL;
- GFileInfo *finfo = NULL;
- GFileInputStream *instream = NULL;
- gboolean pack_builder_initialized = FALSE;
- GVariantBuilder pack_builder;
- GVariant *pack_variant = NULL;
- GVariant *xattrs = NULL;
- gsize bytes_written;
-
- path = g_file_get_path (file);
-
- finfo = g_file_query_info (file, "standard::type,standard::size,standard::is-symlink,standard::symlink-target,unix::*",
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error);
- if (!finfo)
- goto out;
-
- if (objtype == OSTREE_OBJECT_TYPE_META)
- {
- guint64 object_size_be = GUINT64_TO_BE ((guint64)g_file_info_get_size (finfo));
- if (!g_output_stream_write_all (output, &object_size_be, 8, &bytes_written, cancellable, error))
- goto out;
-
- instream = g_file_read (file, NULL, error);
- if (!instream)
- goto out;
-
- if (g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error) < 0)
- goto out;
- }
- else
- {
- guint32 uid, gid, mode;
- guint32 device = 0;
- guint32 metadata_size_be;
- const char *target = NULL;
- guint64 object_size;
-
- uid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_UID);
- gid = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_GID);
- mode = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_MODE);
-
- g_variant_builder_init (&pack_builder, G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT));
- pack_builder_initialized = TRUE;
- g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (0));
- g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (uid));
- g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (gid));
- g_variant_builder_add (&pack_builder, "u", GUINT32_TO_BE (mode));
-
- xattrs = ostree_get_xattrs_for_path (path, error);
- if (!xattrs)
- goto out;
- g_variant_builder_add (&pack_builder, "@a(ayay)", xattrs);
-
- if (S_ISREG (mode))
- {
- object_size = (guint64)g_file_info_get_size (finfo);
- }
- else if (S_ISLNK (mode))
- {
- target = g_file_info_get_attribute_byte_string (finfo, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
- object_size = strlen (target);
- }
- else if (S_ISBLK (mode) || S_ISCHR (mode))
- {
- device = g_file_info_get_attribute_uint32 (finfo, G_FILE_ATTRIBUTE_UNIX_DEVICE);
- object_size = 4;
- }
- else if (S_ISFIFO (mode))
- {
- object_size = 0;
- }
- else
- g_assert_not_reached ();
-
- g_variant_builder_add (&pack_builder, "t", GUINT64_TO_BE (object_size));
- pack_variant = g_variant_builder_end (&pack_builder);
- pack_builder_initialized = FALSE;
-
- metadata_size_be = GUINT32_TO_BE (g_variant_get_size (pack_variant));
-
- if (!g_output_stream_write_all (output, &metadata_size_be, 4,
- &bytes_written, cancellable, error))
- goto out;
- g_assert (bytes_written == 4);
-
- if (!g_output_stream_write_all (output, g_variant_get_data (pack_variant), g_variant_get_size (pack_variant),
- &bytes_written, cancellable, error))
- goto out;
-
- if (S_ISREG (mode))
- {
- instream = g_file_read (file, NULL, error);
- if (!instream)
- goto out;
- bytes_written = g_output_stream_splice (output, (GInputStream*)instream, 0, cancellable, error);
- if (bytes_written < 0)
- goto out;
- if (bytes_written != object_size)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "File size changed unexpectedly");
- goto out;
- }
- }
- else if (S_ISLNK (mode))
- {
- if (!g_output_stream_write_all (output, target, object_size,
- &bytes_written, cancellable, error))
- goto out;
- }
- else if (S_ISBLK (mode) || S_ISCHR (mode))
- {
- guint32 device_be = GUINT32_TO_BE (device);
- g_assert (object_size == 4);
- if (!g_output_stream_write_all (output, &device_be, object_size,
- &bytes_written, cancellable, error))
- goto out;
- g_assert (bytes_written == 4);
- }
- else if (S_ISFIFO (mode))
- {
- }
- else
- g_assert_not_reached ();
- }
-
- ret = TRUE;
- out:
- g_free (path);
- g_clear_object (&finfo);
- g_clear_object (&instream);
- if (xattrs)
- g_variant_unref (xattrs);
- if (pack_builder_initialized)
- g_variant_builder_clear (&pack_builder);
- if (pack_variant)
- g_variant_unref (pack_variant);
- return ret;
-}
-
-static gboolean
-splice_and_checksum (GOutputStream *out,
- GInputStream *in,
- GChecksum *checksum,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
-
- if (checksum != NULL)
- {
- gsize bytes_read, bytes_written;
- char buf[4096];
- do
- {
- if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
- goto out;
- if (checksum)
- g_checksum_update (checksum, (guint8*)buf, bytes_read);
- if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error))
- goto out;
- }
- while (bytes_read > 0);
- }
- else
- {
- if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
- goto out;
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-unpack_meta (const char *path,
- const char *dest_path,
- GChecksum **out_checksum,
- GError **error)
-{
- gboolean ret = FALSE;
- GFile *file = NULL;
- GFile *dest_file = NULL;
- GFileInputStream *in = NULL;
- GChecksum *ret_checksum = NULL;
- GFileOutputStream *out = NULL;
-
- file = ot_util_new_file_for_path (path);
- dest_file = ot_util_new_file_for_path (dest_path);
-
- if (out_checksum)
- ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
-
- in = g_file_read (file, NULL, error);
- if (!in)
- goto out;
-
- out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
- if (!out)
- goto out;
-
- if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error))
- goto out;
-
- if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
- goto out;
-
- ret = TRUE;
- if (out_checksum)
- *out_checksum = ret_checksum;
- ret_checksum = NULL;
- out:
- if (!ret)
- (void) unlink (dest_path);
- if (ret_checksum)
- g_checksum_free (ret_checksum);
- g_clear_object (&file);
- g_clear_object (&dest_file);
- g_clear_object (&in);
- return ret;
-}
-
-gboolean
-ostree_parse_packed_file (GFile *file,
- GVariant **out_metadata,
- GInputStream **out_content,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- char *metadata_buf = NULL;
- GVariant *ret_metadata = NULL;
- GFileInputStream *in = NULL;
- guint32 metadata_len;
- gsize bytes_read;
-
- in = g_file_read (file, NULL, error);
- if (!in)
- goto out;
-
- if (!g_input_stream_read_all ((GInputStream*)in, &metadata_len, 4, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != 4)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading metadata length");
- goto out;
- }
-
- metadata_len = GUINT32_FROM_BE (metadata_len);
- if (metadata_len > OSTREE_MAX_METADATA_SIZE)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; metadata length %u is larger than maximum %u",
- metadata_len, OSTREE_MAX_METADATA_SIZE);
- goto out;
- }
- metadata_buf = g_malloc (metadata_len);
-
- if (!g_input_stream_read_all ((GInputStream*)in, metadata_buf, metadata_len, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != metadata_len)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading metadata");
- goto out;
- }
-
- ret_metadata = g_variant_new_from_data (G_VARIANT_TYPE (OSTREE_PACK_FILE_VARIANT_FORMAT),
- metadata_buf, metadata_len, FALSE,
- (GDestroyNotify)g_free,
- metadata_buf);
- metadata_buf = NULL;
-
- ret = TRUE;
- *out_metadata = ret_metadata;
- ret_metadata = NULL;
- *out_content = (GInputStream*)in;
- in = NULL;
- out:
- g_clear_object (&in);
- if (ret_metadata)
- g_variant_unref (ret_metadata);
- return ret;
-}
-
-static gboolean
-unpack_file (const char *path,
- const char *dest_path,
- GChecksum **out_checksum,
- GError **error)
-{
- gboolean ret = FALSE;
- GFile *file = NULL;
- GFile *dest_file = NULL;
- GVariant *metadata = NULL;
- GVariant *xattrs = NULL;
- GInputStream *in = NULL;
- GFileOutputStream *out = NULL;
- GChecksum *ret_checksum = NULL;
- guint32 version, uid, gid, mode;
- guint64 content_len;
- gsize bytes_read;
-
- file = ot_util_new_file_for_path (path);
-
- if (!ostree_parse_packed_file (file, &metadata, &in, NULL, error))
- goto out;
-
- g_variant_get (metadata, "(uuuu@a(ayay)t)",
- &version, &uid, &gid, &mode,
- &xattrs, &content_len);
- uid = GUINT32_FROM_BE (uid);
- gid = GUINT32_FROM_BE (gid);
- mode = GUINT32_FROM_BE (mode);
- content_len = GUINT64_FROM_BE (content_len);
-
- dest_file = ot_util_new_file_for_path (dest_path);
-
- if (out_checksum)
- ret_checksum = g_checksum_new (G_CHECKSUM_SHA256);
-
- if (S_ISREG (mode))
- {
- out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error);
- if (!out)
- goto out;
-
- if (!splice_and_checksum ((GOutputStream*)out, in, ret_checksum, NULL, error))
- goto out;
-
- if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
- goto out;
- }
- else if (S_ISLNK (mode))
- {
- char target[PATH_MAX+1];
-
- if (!g_input_stream_read_all (in, target, sizeof(target)-1, &bytes_read, NULL, error))
- goto out;
- target[bytes_read] = '\0';
- if (ret_checksum)
- g_checksum_update (ret_checksum, (guint8*)target, bytes_read);
- if (symlink (target, dest_path) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else if (S_ISCHR (mode) || S_ISBLK (mode))
- {
- guint32 dev;
-
- if (!g_input_stream_read_all (in, &dev, 4, &bytes_read, NULL, error))
- goto out;
- if (bytes_read != 4)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; too short while reading device id");
- goto out;
- }
- dev = GUINT32_FROM_BE (dev);
- if (ret_checksum)
- g_checksum_update (ret_checksum, (guint8*)&dev, 4);
- if (mknod (dest_path, mode, dev) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else if (S_ISFIFO (mode))
- {
- if (mkfifo (dest_path, mode) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- else
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile; invalid mode %u", mode);
- goto out;
- }
-
- if (!S_ISLNK (mode))
- {
- if (chmod (dest_path, mode) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
-
- if (!ostree_set_xattrs (dest_path, xattrs, NULL, error))
- goto out;
-
- if (ret_checksum)
- {
- ostree_checksum_update_stat (ret_checksum, uid, gid, mode);
- g_checksum_update (ret_checksum, (guint8*)g_variant_get_data (xattrs), g_variant_get_size (xattrs));
- }
-
- ret = TRUE;
- if (out_checksum)
- *out_checksum = ret_checksum;
- ret_checksum = NULL;
- out:
- if (!ret)
- (void) unlink (dest_path);
- if (ret_checksum)
- g_checksum_free (ret_checksum);
- g_clear_object (&file);
- g_clear_object (&dest_file);
- g_clear_object (&in);
- g_clear_object (&out);
- if (metadata)
- g_variant_unref (metadata);
- if (xattrs)
- g_variant_unref (xattrs);
- return ret;
-}
-
-gboolean
-ostree_unpack_object (const char *path,
- OstreeObjectType objtype,
- const char *dest_path,
- GChecksum **out_checksum,
- GError **error)
-{
- if (objtype == OSTREE_OBJECT_TYPE_META)
- return unpack_meta (path, dest_path, out_checksum, error);
- else
- return unpack_file (path, dest_path, out_checksum, error);
-}
-
-
-
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef _OSTREE_CORE
-#define _OSTREE_CORE
-
-#include <otutil.h>
-
-G_BEGIN_DECLS
-
-#define OSTREE_MAX_METADATA_SIZE (1 << 26)
-
-#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,standard::is-hidden,unix::*"
-
-#define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
-
-typedef enum {
- OSTREE_OBJECT_TYPE_FILE = 1,
- OSTREE_OBJECT_TYPE_META = 2,
-} OstreeObjectType;
-
-typedef enum {
- OSTREE_SERIALIZED_TREE_VARIANT = 1,
- OSTREE_SERIALIZED_COMMIT_VARIANT = 2,
- OSTREE_SERIALIZED_DIRMETA_VARIANT = 3,
- OSTREE_SERIALIZED_XATTR_VARIANT = 4
-} OstreeSerializedVariantType;
-#define OSTREE_SERIALIZED_VARIANT_LAST 4
-
-#define OSTREE_SERIALIZED_VARIANT_FORMAT "(uv)"
-
-/*
- * xattr objects:
- * a(ayay) - array of (name, value) pairs, both binary data, though name is a bytestring
- */
-#define OSTREE_XATTR_GVARIANT_FORMAT "a(ayay)"
-
-#define OSTREE_DIR_META_VERSION 0
-/*
- * dirmeta objects:
- * u - Version
- * u - uid
- * u - gid
- * u - mode
- * a(ayay) - xattrs
- */
-#define OSTREE_DIRMETA_GVARIANT_FORMAT "(uuuua(ayay))"
-
-#define OSTREE_TREE_VERSION 0
-/*
- * Tree objects:
- * u - Version
- * a{sv} - Metadata
- * a(ss) - array of (filename, checksum) for files
- * a(sss) - array of (dirname, tree_checksum, meta_checksum) for directories
- */
-#define OSTREE_TREE_GVARIANT_FORMAT "(ua{sv}a(ss)a(sss)"
-
-#define OSTREE_COMMIT_VERSION 0
-/*
- * Commit objects:
- * u - Version
- * a{sv} - Metadata
- * s - parent checksum (empty string for initial)
- * s - subject
- * s - body
- * t - Timestamp in seconds since the epoch (UTC)
- * s - Root tree contents
- * s - Root tree metadata
- */
-#define OSTREE_COMMIT_GVARIANT_FORMAT "(ua{sv}ssstss)"
-
-gboolean ostree_validate_checksum_string (const char *sha256,
- GError **error);
-
-char *ostree_get_relative_object_path (const char *checksum,
- OstreeObjectType type,
- gboolean archive);
-
-GVariant *ostree_get_xattrs_for_path (const char *path,
- GError **error);
-
-gboolean ostree_set_xattrs (const char *path, GVariant *xattrs,
- GCancellable *cancellable, GError **error);
-
-gboolean ostree_parse_metadata_file (const char *path,
- OstreeSerializedVariantType *out_type,
- GVariant **out_variant,
- GError **error);
-
-gboolean ostree_stat_and_checksum_file (int dirfd, const char *path,
- OstreeObjectType type,
- GChecksum **out_checksum,
- struct stat *out_stbuf,
- GError **error);
-
-/* Packed files:
- *
- * guint32 metadata_length [metadata gvariant] [content]
- *
- * metadata variant:
- * u - Version
- * u - uid
- * u - gid
- * u - mode
- * a(ayay) - xattrs
- * t - content length
- *
- * And then following the end of the variant is the content. If
- * symlink, then this is the target; if device, then device ID as
- * network byte order uint32.
- */
-#define OSTREE_PACK_FILE_VARIANT_FORMAT "(uuuua(ayay)t)"
-
-gboolean ostree_pack_object (GOutputStream *output,
- GFile *file,
- OstreeObjectType objtype,
- GCancellable *cancellable,
- GError **error);
-
-gboolean ostree_parse_packed_file (GFile *file,
- GVariant **out_metadata,
- GInputStream **out_content,
- GCancellable *cancellable,
- GError **error);
-
-gboolean ostree_unpack_object (const char *path,
- OstreeObjectType objtype,
- const char *dest_path,
- GChecksum **out_checksum,
- GError **error);
-
-void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode);
-
-
-#endif /* _OSTREE_REPO */
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ostree-repo-file-enumerator.h"
-#include <string.h>
-
-struct _OstreeRepoFileEnumerator
-{
- GFileEnumerator parent;
-
- OstreeRepoFile *dir;
- char *attributes;
- GFileQueryInfoFlags flags;
-
- int index;
-};
-
-#define ostree_repo_file_enumerator_get_type _ostree_repo_file_enumerator_get_type
-G_DEFINE_TYPE (OstreeRepoFileEnumerator, ostree_repo_file_enumerator, G_TYPE_FILE_ENUMERATOR);
-
-static GFileInfo *ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
- GCancellable *cancellable,
- GError **error);
-static gboolean ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
- GCancellable *cancellable,
- GError **error);
-
-
-static void
-ostree_repo_file_enumerator_dispose (GObject *object)
-{
- OstreeRepoFileEnumerator *self;
-
- self = OSTREE_REPO_FILE_ENUMERATOR (object);
-
- g_clear_object (&self->dir);
- g_free (self->attributes);
-
- if (G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose)
- G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->dispose (object);
-}
-
-static void
-ostree_repo_file_enumerator_finalize (GObject *object)
-{
- OstreeRepoFileEnumerator *self;
-
- self = OSTREE_REPO_FILE_ENUMERATOR (object);
- (void)self;
-
- G_OBJECT_CLASS (ostree_repo_file_enumerator_parent_class)->finalize (object);
-}
-
-
-static void
-ostree_repo_file_enumerator_class_init (OstreeRepoFileEnumeratorClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- GFileEnumeratorClass *enumerator_class = G_FILE_ENUMERATOR_CLASS (klass);
-
- gobject_class->finalize = ostree_repo_file_enumerator_finalize;
- gobject_class->dispose = ostree_repo_file_enumerator_dispose;
-
- enumerator_class->next_file = ostree_repo_file_enumerator_next_file;
- enumerator_class->close_fn = ostree_repo_file_enumerator_close;
-}
-
-static void
-ostree_repo_file_enumerator_init (OstreeRepoFileEnumerator *self)
-{
-}
-
-GFileEnumerator *
-_ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- OstreeRepoFileEnumerator *self;
-
- self = g_object_new (OSTREE_TYPE_REPO_FILE_ENUMERATOR,
- "container", dir,
- NULL);
-
- self->dir = g_object_ref (dir);
- self->attributes = g_strdup (attributes);
- self->flags = flags;
-
- return G_FILE_ENUMERATOR (self);
-}
-
-static GFileInfo *
-ostree_repo_file_enumerator_next_file (GFileEnumerator *enumerator,
- GCancellable *cancellable,
- GError **error)
-{
- OstreeRepoFileEnumerator *self = OSTREE_REPO_FILE_ENUMERATOR (enumerator);
- gboolean ret = FALSE;
- GFileInfo *info = NULL;
-
- if (!_ostree_repo_file_tree_query_child (self->dir, self->index,
- self->attributes, self->flags,
- &info, cancellable, error))
- goto out;
-
- self->index++;
-
- ret = TRUE;
- out:
- if (!ret)
- g_clear_object (&info);
- return info;
-}
-
-static gboolean
-ostree_repo_file_enumerator_close (GFileEnumerator *enumerator,
- GCancellable *cancellable,
- GError **error)
-{
- return TRUE;
-}
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef _OSTREE_REPO_FILE_ENUMERATOR
-#define _OSTREE_REPO_FILE_ENUMERATOR
-
-#include "ostree-repo-file.h"
-
-G_BEGIN_DECLS
-
-#define OSTREE_TYPE_REPO_FILE_ENUMERATOR (_ostree_repo_file_enumerator_get_type ())
-#define OSTREE_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumerator))
-#define OSTREE_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
-#define OSTREE_IS_REPO_FILE_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
-#define OSTREE_IS_REPO_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE_ENUMERATOR))
-#define OSTREE_REPO_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE_ENUMERATOR, OstreeRepoFileEnumeratorClass))
-
-typedef struct _OstreeRepoFileEnumerator OstreeRepoFileEnumerator;
-typedef struct _OstreeRepoFileEnumeratorClass OstreeRepoFileEnumeratorClass;
-
-struct _OstreeRepoFileEnumeratorClass
-{
- GFileEnumeratorClass parent_class;
-};
-
-GType _ostree_repo_file_enumerator_get_type (void) G_GNUC_CONST;
-
-GFileEnumerator * _ostree_repo_file_enumerator_new (OstreeRepoFile *dir,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GCancellable *cancellable,
- GError **error);
-
-G_END_DECLS
-
-#endif
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#include "config.h"
-
-#include "ostree-repo-file-enumerator.h"
-
-static void ostree_repo_file_file_iface_init (GFileIface *iface);
-
-static void
-tree_replace_contents (OstreeRepoFile *self,
- GVariant *new_files,
- GVariant *new_dirs);
-
-struct _OstreeRepoFile
-{
- GObject parent_instance;
-
- OstreeRepo *repo;
-
- char *commit;
- GError *commit_resolve_error;
-
- OstreeRepoFile *parent;
- int index;
- char *name;
-
- char *tree_contents_checksum;
- GVariant *tree_contents;
- char *tree_metadata_checksum;
- GVariant *tree_metadata;
-};
-
-#define ostree_repo_file_get_type _ostree_repo_file_get_type
-G_DEFINE_TYPE_WITH_CODE (OstreeRepoFile, ostree_repo_file, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
- ostree_repo_file_file_iface_init))
-
-static void
-ostree_repo_file_finalize (GObject *object)
-{
- OstreeRepoFile *self;
-
- self = OSTREE_REPO_FILE (object);
-
- if (self->tree_contents)
- g_variant_unref (self->tree_contents);
- if (self->tree_metadata)
- g_variant_unref (self->tree_metadata);
- g_free (self->tree_contents_checksum);
- g_free (self->tree_metadata_checksum);
- g_free (self->commit);
- g_free (self->name);
-
- G_OBJECT_CLASS (ostree_repo_file_parent_class)->finalize (object);
-}
-
-static void
-ostree_repo_file_dispose (GObject *object)
-{
- OstreeRepoFile *self;
-
- self = OSTREE_REPO_FILE (object);
-
- g_clear_object (&self->repo);
- g_clear_object (&self->parent);
-
- if (G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose)
- G_OBJECT_CLASS (ostree_repo_file_parent_class)->dispose (object);
-}
-
-static void
-ostree_repo_file_class_init (OstreeRepoFileClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->finalize = ostree_repo_file_finalize;
- gobject_class->dispose = ostree_repo_file_dispose;
-}
-
-static void
-ostree_repo_file_init (OstreeRepoFile *self)
-{
- self->index = -1;
-}
-
-static gboolean
-set_error_noent (GFile *self, GError **error)
-{
- char *path = g_file_get_path (self);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- "No such file or directory: %s", path);
- g_free (path);
- return FALSE;
-}
-
-GFile *
-_ostree_repo_file_new_root (OstreeRepo *repo,
- const char *commit)
-{
- OstreeRepoFile *self;
-
- g_return_val_if_fail (repo != NULL, NULL);
- g_return_val_if_fail (commit != NULL, NULL);
- g_return_val_if_fail (strlen (commit) == 64, NULL);
-
- self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
- self->repo = g_object_ref (repo);
- self->commit = g_strdup (commit);
-
- return G_FILE (self);
-}
-
-
-GFile *
-_ostree_repo_file_new_child (OstreeRepoFile *parent,
- const char *name)
-{
- OstreeRepoFile *self;
-
- self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
- self->repo = g_object_ref (parent->repo);
- self->parent = g_object_ref (parent);
- self->name = g_strdup (name);
-
- return G_FILE (self);
-}
-
-OstreeRepoFile *
-_ostree_repo_file_new_empty_tree (OstreeRepo *repo)
-{
- OstreeRepoFile *self;
-
- self = g_object_new (OSTREE_TYPE_REPO_FILE, NULL);
- self->repo = g_object_ref (repo);
-
- tree_replace_contents (self, NULL, NULL);
-
- return self;
-}
-
-static gboolean
-do_resolve_commit (OstreeRepoFile *self,
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *commit = NULL;
- GVariant *root_contents = NULL;
- GVariant *root_metadata = NULL;
- const char *tree_contents_checksum;
- const char *tree_meta_checksum;
-
- g_assert (self->parent == NULL);
-
- if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_COMMIT_VARIANT,
- self->commit, &commit, error))
- goto out;
-
- /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */
- g_variant_get_child (commit, 6, "&s", &tree_contents_checksum);
- g_variant_get_child (commit, 7, "&s", &tree_meta_checksum);
-
- if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_TREE_VARIANT,
- tree_contents_checksum, &root_contents,
- error))
- goto out;
-
- if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- tree_meta_checksum, &root_metadata,
- error))
- goto out;
-
- self->tree_metadata = root_metadata;
- root_metadata = NULL;
- self->tree_contents = root_contents;
- root_contents = NULL;
-
- out:
- if (commit)
- g_variant_unref (commit);
- if (root_metadata)
- g_variant_unref (root_metadata);
- if (root_contents)
- g_variant_unref (root_contents);
- return ret;
-}
-
-static gboolean
-do_resolve_nonroot (OstreeRepoFile *self,
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *container = NULL;
- GVariant *tree_contents = NULL;
- GVariant *tree_metadata = NULL;
- gboolean is_dir;
- int i;
-
- i = _ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, &container);
-
- if (i < 0)
- {
- set_error_noent ((GFile*)self, error);
- goto out;
- }
-
- if (is_dir)
- {
- const char *name;
- const char *content_checksum;
- const char *metadata_checksum;
- GVariant *files_variant;
-
- files_variant = g_variant_get_child_value (self->parent->tree_contents, 2);
- self->index = g_variant_n_children (files_variant) + i;
- g_variant_unref (files_variant);
-
- g_variant_get_child (container, i, "(&s&s&s)",
- &name, &content_checksum, &metadata_checksum);
-
- if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_TREE_VARIANT,
- content_checksum, &tree_contents,
- error))
- goto out;
-
- if (!ostree_repo_load_variant_checked (self->repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- metadata_checksum, &tree_metadata,
- error))
- goto out;
-
- self->tree_contents = tree_contents;
- tree_contents = NULL;
- self->tree_metadata = tree_metadata;
- tree_metadata = NULL;
- }
- else
- self->index = i;
-
- ret = TRUE;
- out:
- if (container)
- g_variant_unref (container);
- if (tree_metadata)
- g_variant_unref (tree_metadata);
- if (tree_contents)
- g_variant_unref (tree_contents);
- return ret;
-}
-
-gboolean
-_ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
- GError **error)
-{
- if (self->commit_resolve_error != NULL)
- goto out;
-
- if (self->parent == NULL)
- {
- if (self->tree_contents == NULL)
- (void)do_resolve_commit (self, &(self->commit_resolve_error));
- }
- else if (self->index == -1)
- {
- (void)do_resolve_nonroot (self, &(self->commit_resolve_error));
- }
-
- out:
- if (self->commit_resolve_error)
- {
- if (error)
- *error = g_error_copy (self->commit_resolve_error);
- return FALSE;
- }
- else
- return TRUE;
-}
-
-gboolean
-_ostree_repo_file_get_xattrs (OstreeRepoFile *self,
- GVariant **out_xattrs,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *ret_xattrs = NULL;
- GVariant *metadata = NULL;
- GInputStream *input = NULL;
- GFile *local_file = NULL;
-
- if (!_ostree_repo_file_ensure_resolved (self, error))
- goto out;
-
- if (self->tree_metadata)
- ret_xattrs = g_variant_get_child_value (self->tree_metadata, 4);
- else if (ostree_repo_is_archive (self->repo))
- {
- local_file = _ostree_repo_file_nontree_get_local (self);
- if (!ostree_parse_packed_file (local_file, &metadata, &input, cancellable, error))
- goto out;
- ret_xattrs = g_variant_get_child_value (metadata, 4);
- }
- else
- {
- local_file = _ostree_repo_file_nontree_get_local (self);
- ret_xattrs = ostree_get_xattrs_for_path (ot_gfile_get_path_cached (local_file), error);
- }
-
- ret = TRUE;
- *out_xattrs = ret_xattrs;
- ret_xattrs = NULL;
- out:
- if (ret_xattrs)
- g_variant_unref (ret_xattrs);
- if (metadata)
- g_variant_unref (metadata);
- g_clear_object (&input);
- g_clear_object (&local_file);
- return ret;
-}
-
-GVariant *
-_ostree_repo_file_tree_get_contents (OstreeRepoFile *self)
-{
- return self->tree_contents;
-}
-
-GVariant *
-_ostree_repo_file_tree_get_metadata (OstreeRepoFile *self)
-{
- return self->tree_metadata;
-}
-
-void
-_ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
- const char *checksum,
- GVariant *metadata)
-{
- if (self->tree_metadata)
- g_variant_unref (self->tree_metadata);
- self->tree_metadata = g_variant_ref (metadata);
- g_free (self->tree_metadata_checksum);
- self->tree_metadata_checksum = g_strdup (checksum);
-}
-
-void
-_ostree_repo_file_make_empty_tree (OstreeRepoFile *self)
-{
- tree_replace_contents (self, NULL, NULL);
-}
-
-void
-_ostree_repo_file_tree_set_content_checksum (OstreeRepoFile *self,
- const char *checksum)
-{
- g_assert (self->parent == NULL);
- g_free (self->tree_contents_checksum);
- self->tree_contents_checksum = g_strdup (checksum);
-}
-
-const char *
-_ostree_repo_file_tree_get_content_checksum (OstreeRepoFile *self)
-{
- g_assert (self->parent == NULL);
- return self->tree_contents_checksum;
-}
-
-GFile *
-_ostree_repo_file_nontree_get_local (OstreeRepoFile *self)
-{
- const char *checksum;
- char *path;
- GFile *ret;
-
- g_assert (!ostree_repo_is_archive (self->repo));
-
- checksum = _ostree_repo_file_nontree_get_checksum (self);
- path = ostree_repo_get_object_path (self->repo, checksum, OSTREE_OBJECT_TYPE_FILE);
- ret = ot_util_new_file_for_path (path);
- g_free (path);
-
- return ret;
-}
-
-OstreeRepo *
-_ostree_repo_file_get_repo (OstreeRepoFile *self)
-{
- return self->repo;
-}
-
-OstreeRepoFile *
-_ostree_repo_file_get_root (OstreeRepoFile *self)
-{
- OstreeRepoFile *parent = self;
-
- while (parent->parent)
- parent = parent->parent;
- return parent;
-}
-
-const char *
-_ostree_repo_file_nontree_get_checksum (OstreeRepoFile *self)
-{
- int n;
- gboolean is_dir;
-
- g_assert (self->parent);
-
- n = _ostree_repo_file_tree_find_child (self->parent, self->name, &is_dir, NULL);
- g_assert (n >= 0 && !is_dir);
-
- return _ostree_repo_file_tree_get_child_checksum (self->parent, n);
-}
-
-const char *
-_ostree_repo_file_tree_get_child_checksum (OstreeRepoFile *self,
- int n)
-{
- GVariant *files_variant;
- const char *checksum;
-
- g_assert (self->tree_contents);
-
- files_variant = g_variant_get_child_value (self->tree_contents, 2);
-
- g_variant_get_child (files_variant, n, "(@s&s)", NULL, &checksum);
-
- g_variant_unref (files_variant);
-
- return checksum;
-}
-
-static gboolean
-ostree_repo_file_is_native (GFile *file)
-{
- return FALSE;
-}
-
-static gboolean
-ostree_repo_file_has_uri_scheme (GFile *file,
- const char *uri_scheme)
-{
- return g_ascii_strcasecmp (uri_scheme, "ostree") == 0;
-}
-
-static char *
-ostree_repo_file_get_uri_scheme (GFile *file)
-{
- return g_strdup ("ostree");
-}
-
-static char *
-ostree_repo_file_get_basename (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- return g_strdup (self->name);
-}
-
-static char *
-ostree_repo_file_get_path (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- OstreeRepoFile *parent;
- GString *buf;
- GSList *parents;
- GSList *iter;
-
- buf = g_string_new ("");
- parents = NULL;
-
- for (parent = self->parent; parent; parent = parent->parent)
- parents = g_slist_prepend (parents, parent);
-
- if (parents->next)
- {
- for (iter = parents->next; iter; iter = iter->next)
- {
- parent = iter->data;
- g_string_append_c (buf, '/');
- g_string_append (buf, parent->name);
- }
- }
- g_string_append_c (buf, '/');
- g_string_append (buf, self->name);
-
- g_slist_free (parents);
-
- return g_string_free (buf, FALSE);
-}
-
-static char *
-ostree_repo_file_get_uri (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- char *path;
- char *uri_path;
- char *ret;
-
- path = g_file_get_path (file);
- uri_path = g_filename_to_uri (path, NULL, NULL);
- g_free (path);
- g_assert (g_str_has_prefix (uri_path, "file://"));
- ret = g_strconcat ("ostree://", self->commit, uri_path+strlen("file://"), NULL);
- g_free (uri_path);
-
- return ret;
-}
-
-static char *
-ostree_repo_file_get_parse_name (GFile *file)
-{
- return ostree_repo_file_get_uri (file);
-}
-
-static GFile *
-ostree_repo_file_get_parent (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
-
- return g_object_ref (self->parent);
-}
-
-static GFile *
-ostree_repo_file_dup (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
-
- if (self->parent)
- return _ostree_repo_file_new_child (self->parent, self->name);
- else
- return _ostree_repo_file_new_root (self->repo, self->commit);
-}
-
-static guint
-ostree_repo_file_hash (GFile *file)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
-
- if (self->parent)
- return g_file_hash (self->parent) + g_str_hash (self->name);
- else
- return g_str_hash (self->commit);
-}
-
-static gboolean
-ostree_repo_file_equal (GFile *file1,
- GFile *file2)
-{
- OstreeRepoFile *self1 = OSTREE_REPO_FILE (file1);
- OstreeRepoFile *self2 = OSTREE_REPO_FILE (file2);
-
- if (self1->parent && self2->parent)
- {
- return g_str_equal (self1->name, self2->name)
- && g_file_equal ((GFile*)self1->parent, (GFile*)self2->parent);
- }
- else if (!self1->parent && !self2->parent)
- {
- return g_str_equal (self1->commit, self2->commit);
- }
- else
- return FALSE;
-}
-
-static const char *
-match_prefix (const char *path,
- const char *prefix)
-{
- int prefix_len;
-
- prefix_len = strlen (prefix);
- if (strncmp (path, prefix, prefix_len) != 0)
- return NULL;
-
- /* Handle the case where prefix is the root, so that
- * the IS_DIR_SEPRARATOR check below works */
- if (prefix_len > 0 &&
- G_IS_DIR_SEPARATOR (prefix[prefix_len-1]))
- prefix_len--;
-
- return path + prefix_len;
-}
-
-static gboolean
-ostree_repo_file_prefix_matches (GFile *parent,
- GFile *descendant)
-{
- const char *remainder;
- char *parent_path;
- char *descendant_path;
-
- parent_path = g_file_get_path (parent);
- descendant_path = g_file_get_path (descendant);
- remainder = match_prefix (descendant_path, parent_path);
- g_free (parent_path);
- g_free (descendant_path);
- if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
- return TRUE;
- return FALSE;
-}
-
-static char *
-ostree_repo_file_get_relative_path (GFile *parent,
- GFile *descendant)
-{
- const char *remainder;
- char *parent_path;
- char *descendant_path;
-
- parent_path = g_file_get_path (parent);
- descendant_path = g_file_get_path (descendant);
- remainder = match_prefix (descendant_path, parent_path);
- g_free (parent_path);
- g_free (descendant_path);
-
- if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
- return g_strdup (remainder + 1);
- return NULL;
-}
-
-static GFile *
-ostree_repo_file_resolve_relative_path (GFile *file,
- const char *relative_path)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- OstreeRepoFile *parent;
- char *filename;
- const char *rest;
- GFile *ret;
-
- if (g_path_is_absolute (relative_path) && self->parent)
- {
- g_assert (*relative_path == '/');
- return ostree_repo_file_resolve_relative_path ((GFile*)_ostree_repo_file_get_root (self),
- relative_path+1);
- }
-
- rest = strchr (relative_path, '/');
- if (rest)
- {
- rest += 1;
- filename = g_strndup (relative_path, rest - relative_path);
- }
- else
- filename = g_strdup (relative_path);
-
- parent = (OstreeRepoFile*)_ostree_repo_file_new_child (self, filename);
- g_free (filename);
-
- if (!rest)
- ret = (GFile*)parent;
- else
- {
- ret = ostree_repo_file_resolve_relative_path ((GFile*)parent, rest);
- g_clear_object (&parent);
- }
- return ret;
-}
-
-static GFileEnumerator *
-ostree_repo_file_enumerate_children (GFile *file,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- return _ostree_repo_file_enumerator_new (self,
- attributes, flags,
- cancellable, error);
-}
-
-static GFile *
-ostree_repo_file_get_child_for_display_name (GFile *file,
- const char *display_name,
- GError **error)
-{
- return g_file_get_child (file, display_name);
-}
-
-static GFile *
-get_child_local_file (OstreeRepo *repo,
- const char *checksum)
-{
- char *path;
- GFile *ret;
-
- path = ostree_repo_get_object_path (repo, checksum, OSTREE_OBJECT_TYPE_FILE);
- ret = ot_util_new_file_for_path (path);
- g_free (path);
-
- return ret;
-}
-
-static gboolean
-query_child_info_file_nonarchive (OstreeRepo *repo,
- const char *checksum,
- GFileAttributeMatcher *matcher,
- GFileInfo *info,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GFileInfo *local_info = NULL;
- GFile *local_file = NULL;
- int i ;
- const char *mapped_boolean[] = {
- "standard::is-symlink"
- };
- const char *mapped_string[] = {
- };
- const char *mapped_byte_string[] = {
- "standard::symlink-target"
- };
- const char *mapped_uint32[] = {
- "standard::type",
- "unix::device",
- "unix::mode",
- "unix::nlink",
- "unix::uid",
- "unix::gid",
- "unix::rdev"
- };
- const char *mapped_uint64[] = {
- "standard::size",
- "standard::allocated-size",
- "unix::inode"
- };
-
- if (!(g_file_attribute_matcher_matches (matcher, "unix::mode")
- || g_file_attribute_matcher_matches (matcher, "standard::type")))
- {
- ret = TRUE;
- goto out;
- }
-
- local_file = get_child_local_file (repo, checksum);
- local_info = g_file_query_info (local_file,
- OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable,
- error);
- if (!local_info)
- goto out;
-
- for (i = 0; i < G_N_ELEMENTS (mapped_boolean); i++)
- g_file_info_set_attribute_boolean (info, mapped_boolean[i], g_file_info_get_attribute_boolean (local_info, mapped_boolean[i]));
-
- for (i = 0; i < G_N_ELEMENTS (mapped_string); i++)
- {
- const char *string = g_file_info_get_attribute_string (local_info, mapped_string[i]);
- if (string)
- g_file_info_set_attribute_string (info, mapped_string[i], string);
- }
-
- for (i = 0; i < G_N_ELEMENTS (mapped_byte_string); i++)
- {
- const char *byte_string = g_file_info_get_attribute_byte_string (local_info, mapped_byte_string[i]);
- if (byte_string)
- g_file_info_set_attribute_byte_string (info, mapped_byte_string[i], byte_string);
- }
-
- for (i = 0; i < G_N_ELEMENTS (mapped_uint32); i++)
- g_file_info_set_attribute_uint32 (info, mapped_uint32[i], g_file_info_get_attribute_uint32 (local_info, mapped_uint32[i]));
-
- for (i = 0; i < G_N_ELEMENTS (mapped_uint64); i++)
- g_file_info_set_attribute_uint64 (info, mapped_uint64[i], g_file_info_get_attribute_uint64 (local_info, mapped_uint64[i]));
-
- ret = TRUE;
- out:
- g_clear_object (&local_info);
- g_clear_object (&local_file);
- return ret;
-}
-
-static gboolean
-query_child_info_file_archive (OstreeRepo *repo,
- const char *checksum,
- GFileAttributeMatcher *matcher,
- GFileInfo *info,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GFile *local_file = NULL;
- GVariant *metadata = NULL;
- GInputStream *input = NULL;
- guint32 version, uid, gid, mode;
- guint64 content_len;
- guint32 file_type;
- gsize bytes_read;
- char *buf = NULL;
-
- local_file = get_child_local_file (repo, checksum);
-
- if (!ostree_parse_packed_file (local_file, &metadata, &input, cancellable, error))
- goto out;
-
- g_variant_get (metadata, "(uuuu@a(ayay)t)",
- &version, &uid, &gid, &mode,
- NULL, &content_len);
- uid = GUINT32_FROM_BE (uid);
- gid = GUINT32_FROM_BE (gid);
- mode = GUINT32_FROM_BE (mode);
- content_len = GUINT64_FROM_BE (content_len);
-
- g_file_info_set_attribute_boolean (info, "standard::is-symlink",
- S_ISLNK (mode));
- if (S_ISLNK (mode))
- file_type = G_FILE_TYPE_SYMBOLIC_LINK;
- else if (S_ISREG (mode))
- file_type = G_FILE_TYPE_REGULAR;
- else if (S_ISBLK (mode) || S_ISCHR(mode) || S_ISFIFO(mode))
- file_type = G_FILE_TYPE_SPECIAL;
- else
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted packfile %s: Invalid mode", checksum);
- goto out;
- }
- g_file_info_set_attribute_uint32 (info, "standard::type", file_type);
-
- g_file_info_set_attribute_uint32 (info, "unix::uid", uid);
- g_file_info_set_attribute_uint32 (info, "unix::gid", gid);
- g_file_info_set_attribute_uint32 (info, "unix::mode", mode);
-
- if (file_type == G_FILE_TYPE_REGULAR)
- {
- g_file_info_set_attribute_uint64 (info, "standard::size", content_len);
- }
- else if (file_type == G_FILE_TYPE_SYMBOLIC_LINK)
- {
- gsize len = MIN (PATH_MAX, content_len) + 1;
- buf = g_malloc (len);
-
- if (!g_input_stream_read_all (input, buf, len, &bytes_read, cancellable, error))
- goto out;
- buf[bytes_read] = '\0';
-
- g_file_info_set_attribute_byte_string (info, "standard::symlink-target", buf);
- }
- else if (file_type == G_FILE_TYPE_SPECIAL)
- {
- guint32 device;
-
- if (!g_input_stream_read_all (input, &device, 4, &bytes_read, cancellable, error))
- goto out;
-
- device = GUINT32_FROM_BE (device);
- g_file_info_set_attribute_uint32 (info, "unix::device", device);
- }
-
- ret = TRUE;
- out:
- g_free (buf);
- if (metadata)
- g_variant_unref (metadata);
- g_clear_object (&local_file);
- g_clear_object (&input);
- return ret;
-}
-
-static void
-set_info_from_dirmeta (GFileInfo *info,
- GVariant *metadata)
-{
- guint32 version, uid, gid, mode;
-
- g_file_info_set_attribute_uint32 (info, "standard::type", G_FILE_TYPE_DIRECTORY);
-
- /* PARSE OSTREE_SERIALIZED_DIRMETA_VARIANT */
- g_variant_get (metadata, "(uuuu@a(ayay))",
- &version, &uid, &gid, &mode,
- NULL);
- version = GUINT32_FROM_BE (version);
- uid = GUINT32_FROM_BE (uid);
- gid = GUINT32_FROM_BE (gid);
- mode = GUINT32_FROM_BE (mode);
-
- g_file_info_set_attribute_uint32 (info, "unix::uid", uid);
- g_file_info_set_attribute_uint32 (info, "unix::gid", gid);
- g_file_info_set_attribute_uint32 (info, "unix::mode", mode);
-}
-
-static gboolean
-query_child_info_dir (OstreeRepo *repo,
- const char *metadata_checksum,
- GFileAttributeMatcher *matcher,
- GFileQueryInfoFlags flags,
- GFileInfo *info,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *metadata = NULL;
-
- if (!g_file_attribute_matcher_matches (matcher, "unix::mode"))
- {
- ret = TRUE;
- goto out;
- }
-
- if (!ostree_repo_load_variant_checked (repo, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- metadata_checksum, &metadata, error))
- goto out;
-
- set_info_from_dirmeta (info, metadata);
-
- ret = TRUE;
- out:
- if (metadata)
- g_variant_unref (metadata);
- return ret;
-}
-
-static gboolean
-bsearch_in_file_variant (GVariant *variant,
- const char *name,
- int *out_pos)
-{
- int i, n;
- int m;
-
- i = 0;
- n = g_variant_n_children (variant) - 1;
- m = 0;
-
- while (i <= n)
- {
- GVariant *child;
- const char *cur;
- int cmp;
-
- m = i + ((n - i) / 2);
-
- child = g_variant_get_child_value (variant, m);
- g_variant_get_child (child, 0, "&s", &cur, NULL);
-
- cmp = strcmp (cur, name);
- if (cmp < 0)
- i = m + 1;
- else if (cmp > 0)
- n = m - 1;
- else
- {
- g_variant_unref (child);
- *out_pos = m;
- return TRUE;
- }
- g_variant_unref (child);
- }
-
- *out_pos = m;
- return FALSE;
-}
-
-static GVariant *
-remove_variant_child (GVariant *variant,
- int n)
-{
- GVariantBuilder builder;
- GVariantIter *iter;
- int i;
- GVariant *child;
-
- g_variant_builder_init (&builder, g_variant_get_type (variant));
- iter = g_variant_iter_new (variant);
-
- i = 0;
- while ((child = g_variant_iter_next_value (iter)) != NULL)
- {
- if (i != n)
- g_variant_builder_add_value (&builder, child);
- g_variant_unref (child);
- }
- g_variant_iter_free (iter);
-
- return g_variant_builder_end (&builder);
-}
-
-static GVariant *
-insert_variant_child (GVariant *variant,
- int n,
- GVariant *item)
-{
- GVariantBuilder builder;
- GVariantIter *iter;
- int i;
- GVariant *child;
-
- g_variant_builder_init (&builder, g_variant_get_type (variant));
- iter = g_variant_iter_new (variant);
-
- i = 0;
- while ((child = g_variant_iter_next_value (iter)) != NULL)
- {
- if (i == n)
- g_variant_builder_add_value (&builder, item);
- g_variant_builder_add_value (&builder, child);
- g_variant_unref (child);
- }
- g_variant_iter_free (iter);
-
- return g_variant_builder_end (&builder);
-}
-
-static void
-tree_replace_contents (OstreeRepoFile *self,
- GVariant *new_files,
- GVariant *new_dirs)
-{
- guint version;
- GVariant *metadata;
- GVariant *tmp_files = NULL;
- GVariant *tmp_dirs = NULL;
-
- if (!(new_files || new_dirs) && self->tree_contents)
- return;
- else if (!self->tree_contents)
- {
- version = GUINT32_TO_BE (0);
- metadata = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0);
- tmp_dirs = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), NULL, 0);
- tmp_files = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), NULL, 0);
- }
- else
- {
- g_variant_get_child (self->tree_contents, 0, "u", &version);
- metadata = g_variant_get_child_value (self->tree_contents, 1);
- if (!new_files)
- tmp_files = g_variant_get_child_value (self->tree_contents, 2);
- if (!new_dirs)
- tmp_dirs = g_variant_get_child_value (self->tree_contents, 3);
- }
-
- if (self->tree_contents)
- g_variant_unref (self->tree_contents);
- self->tree_contents = g_variant_new ("(u@a{sv}@a(ss)@a(sss))", version, metadata,
- new_files ? new_files : tmp_files,
- new_dirs ? new_dirs : tmp_dirs);
-
- g_variant_unref (metadata);
- if (tmp_files)
- g_variant_unref (tmp_files);
- if (tmp_dirs)
- g_variant_unref (tmp_dirs);
-}
-
-void
-_ostree_repo_file_tree_remove_child (OstreeRepoFile *self,
- const char *name)
-{
- int i;
- GVariant *files_variant;
- GVariant *new_files_variant = NULL;
- GVariant *dirs_variant;
- GVariant *new_dirs_variant = NULL;
-
- files_variant = g_variant_get_child_value (self->tree_contents, 2);
- dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
-
- if (bsearch_in_file_variant (files_variant, name, &i))
- {
- new_files_variant = remove_variant_child (files_variant, i);
- }
- else
- {
- if (bsearch_in_file_variant (dirs_variant, name, &i))
- {
- new_dirs_variant = remove_variant_child (dirs_variant, i);
- }
- }
-
- tree_replace_contents (self, new_files_variant, new_dirs_variant);
-
- g_variant_unref (files_variant);
- g_variant_unref (dirs_variant);
-}
-
-void
-_ostree_repo_file_tree_add_file (OstreeRepoFile *self,
- const char *name,
- const char *checksum)
-{
- int n;
- GVariant *files_variant;
- GVariant *new_files_variant;
-
- files_variant = g_variant_get_child_value (self->tree_contents, 2);
-
- if (!bsearch_in_file_variant (files_variant, name, &n))
- {
- new_files_variant = insert_variant_child (files_variant, n,
- g_variant_new ("(ss)", name, checksum));
- g_variant_ref_sink (new_files_variant);
- tree_replace_contents (self, new_files_variant, NULL);
- g_variant_unref (new_files_variant);
- }
- g_variant_unref (files_variant);
-}
-
-void
-_ostree_repo_file_tree_add_dir (OstreeRepoFile *self,
- const char *name,
- const char *content_checksum,
- const char *metadata_checksum)
-{
- int n;
- GVariant *dirs_variant;
- GVariant *new_dirs_variant;
-
- dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
-
- if (!bsearch_in_file_variant (dirs_variant, name, &n))
- {
- new_dirs_variant = insert_variant_child (dirs_variant, n,
- g_variant_new ("(sss)", name, content_checksum,
- metadata_checksum));
- g_variant_ref_sink (new_dirs_variant);
- tree_replace_contents (self, NULL, new_dirs_variant);
- g_variant_unref (new_dirs_variant);
- }
- g_variant_unref (dirs_variant);
-}
-
-int
-_ostree_repo_file_tree_find_child (OstreeRepoFile *self,
- const char *name,
- gboolean *is_dir,
- GVariant **out_container)
-{
- int i;
- GVariant *files_variant = NULL;
- GVariant *dirs_variant = NULL;
- GVariant *ret_container = NULL;
-
- files_variant = g_variant_get_child_value (self->tree_contents, 2);
- dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
-
- i = -1;
- if (bsearch_in_file_variant (files_variant, name, &i))
- {
- *is_dir = FALSE;
- ret_container = files_variant;
- files_variant = NULL;
- }
- else
- {
- if (bsearch_in_file_variant (dirs_variant, name, &i))
- {
- *is_dir = TRUE;
- ret_container = dirs_variant;
- dirs_variant = NULL;
- }
- else
- {
- i = -1;
- }
- }
- if (ret_container && out_container)
- {
- *out_container = ret_container;
- ret_container = NULL;
- }
- if (ret_container)
- g_variant_unref (ret_container);
- if (files_variant)
- g_variant_unref (files_variant);
- if (dirs_variant)
- g_variant_unref (dirs_variant);
- return i;
-}
-
-gboolean
-_ostree_repo_file_tree_query_child (OstreeRepoFile *self,
- int n,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GFileInfo **out_info,
- GCancellable *cancellable,
- GError **error)
-{
- const char *name = NULL;
- gboolean ret = FALSE;
- GFileInfo *ret_info = NULL;
- GVariant *files_variant = NULL;
- GVariant *dirs_variant = NULL;
- GVariant *tree_child_metadata = NULL;
- GFileAttributeMatcher *matcher = NULL;
- int c;
-
- if (!_ostree_repo_file_ensure_resolved (self, error))
- goto out;
-
- matcher = g_file_attribute_matcher_new (attributes);
-
- ret_info = g_file_info_new ();
-
- g_assert (self->tree_contents);
-
- files_variant = g_variant_get_child_value (self->tree_contents, 2);
- dirs_variant = g_variant_get_child_value (self->tree_contents, 3);
-
- c = g_variant_n_children (files_variant);
- if (n < c)
- {
- const char *checksum;
-
- g_variant_get_child (files_variant, n, "(&s&s)", &name, &checksum);
-
- if (ostree_repo_is_archive (self->repo))
- {
- if (!query_child_info_file_archive (self->repo, checksum, matcher, ret_info,
- cancellable, error))
- goto out;
- }
- else
- {
- if (!query_child_info_file_nonarchive (self->repo, checksum, matcher, ret_info,
- cancellable, error))
- goto out;
- }
- }
- else
- {
- const char *tree_checksum;
- const char *meta_checksum;
-
- n -= c;
-
- c = g_variant_n_children (dirs_variant);
-
- if (n < c)
- {
- g_variant_get_child (dirs_variant, n, "(&s&s&s)",
- &name, &tree_checksum, &meta_checksum);
-
- if (!query_child_info_dir (self->repo, meta_checksum,
- matcher, flags, ret_info,
- cancellable, error))
- goto out;
- }
- else
- n -= c;
- }
-
- if (name)
- {
- g_file_info_set_attribute_byte_string (ret_info, "standard::name",
- name);
- g_file_info_set_attribute_string (ret_info, "standard::display-name",
- name);
- if (*name == '.')
- g_file_info_set_is_hidden (ret_info, TRUE);
- }
- else
- {
- g_clear_object (&ret_info);
- }
-
- ret = TRUE;
- *out_info = ret_info;
- ret_info = NULL;
- out:
- g_clear_object (&ret_info);
- if (matcher)
- g_file_attribute_matcher_unref (matcher);
- if (tree_child_metadata)
- g_variant_unref (tree_child_metadata);
- g_variant_unref (files_variant);
- g_variant_unref (dirs_variant);
- return ret;
-}
-
-static GFileInfo *
-ostree_repo_file_query_info (GFile *file,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
- gboolean ret = FALSE;
- GFileInfo *info = NULL;
-
- if (!_ostree_repo_file_ensure_resolved (self, error))
- goto out;
-
- if (!self->parent)
- {
- info = g_file_info_new ();
- set_info_from_dirmeta (info, self->tree_metadata);
- }
- else
- {
- if (!_ostree_repo_file_tree_query_child (self->parent, self->index,
- attributes, flags,
- &info, cancellable, error))
- goto out;
- }
-
- ret = TRUE;
- out:
- if (!ret)
- g_clear_object (&info);
- return info;
-}
-
-static GFileAttributeInfoList *
-ostree_repo_file_query_settable_attributes (GFile *file,
- GCancellable *cancellable,
- GError **error)
-{
- return g_file_attribute_info_list_new ();
-}
-
-static GFileAttributeInfoList *
-ostree_repo_file_query_writable_namespaces (GFile *file,
- GCancellable *cancellable,
- GError **error)
-{
- return g_file_attribute_info_list_new ();
-}
-
-static GFileInputStream *
-ostree_repo_file_read (GFile *file,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GFile *local_file = NULL;
- GFileInputStream *ret_stream = NULL;
- OstreeRepoFile *self = OSTREE_REPO_FILE (file);
-
- if (self->tree_contents)
- {
- g_set_error_literal (error, G_IO_ERROR,
- G_IO_ERROR_IS_DIRECTORY,
- "Can't open directory");
- goto out;
- }
-
- if (ostree_repo_is_archive (self->repo))
- {
- g_set_error_literal (error, G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "Can't open archived file (yet)");
- goto out;
- }
- else
- {
- local_file = _ostree_repo_file_nontree_get_local (self);
- ret_stream = g_file_read (local_file, cancellable, error);
- if (!ret_stream)
- goto out;
- }
-
- ret = TRUE;
- out:
- g_clear_object (&local_file);
- if (!ret)
- g_clear_object (&ret_stream);
- return ret_stream;
-}
-
-static void
-ostree_repo_file_file_iface_init (GFileIface *iface)
-{
- iface->dup = ostree_repo_file_dup;
- iface->hash = ostree_repo_file_hash;
- iface->equal = ostree_repo_file_equal;
- iface->is_native = ostree_repo_file_is_native;
- iface->has_uri_scheme = ostree_repo_file_has_uri_scheme;
- iface->get_uri_scheme = ostree_repo_file_get_uri_scheme;
- iface->get_basename = ostree_repo_file_get_basename;
- iface->get_path = ostree_repo_file_get_path;
- iface->get_uri = ostree_repo_file_get_uri;
- iface->get_parse_name = ostree_repo_file_get_parse_name;
- iface->get_parent = ostree_repo_file_get_parent;
- iface->prefix_matches = ostree_repo_file_prefix_matches;
- iface->get_relative_path = ostree_repo_file_get_relative_path;
- iface->resolve_relative_path = ostree_repo_file_resolve_relative_path;
- iface->get_child_for_display_name = ostree_repo_file_get_child_for_display_name;
- iface->set_display_name = NULL;
- iface->enumerate_children = ostree_repo_file_enumerate_children;
- iface->query_info = ostree_repo_file_query_info;
- iface->query_filesystem_info = NULL;
- iface->find_enclosing_mount = NULL;
- iface->query_settable_attributes = ostree_repo_file_query_settable_attributes;
- iface->query_writable_namespaces = ostree_repo_file_query_writable_namespaces;
- iface->set_attribute = NULL;
- iface->set_attributes_from_info = NULL;
- iface->read_fn = ostree_repo_file_read;
- iface->append_to = NULL;
- iface->create = NULL;
- iface->replace = NULL;
- iface->open_readwrite = NULL;
- iface->create_readwrite = NULL;
- iface->replace_readwrite = NULL;
- iface->delete_file = NULL;
- iface->trash = NULL;
- iface->make_directory = NULL;
- iface->make_symbolic_link = NULL;
- iface->copy = NULL;
- iface->move = NULL;
- iface->monitor_dir = NULL;
- iface->monitor_file = NULL;
-
- iface->supports_thread_contexts = TRUE;
-}
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef _OSTREE_REPO_FILE
-#define _OSTREE_REPO_FILE
-
-#include "ostree-repo.h"
-
-G_BEGIN_DECLS
-
-#define OSTREE_TYPE_REPO_FILE (_ostree_repo_file_get_type ())
-#define OSTREE_REPO_FILE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFile))
-#define OSTREE_REPO_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
-#define OSTREE_IS_LOCAL_FILE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_REPO_FILE))
-#define OSTREE_IS_LOCAL_FILE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_REPO_FILE))
-#define OSTREE_REPO_FILE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_REPO_FILE, OstreeRepoFileClass))
-
-typedef struct _OstreeRepoFile OstreeRepoFile;
-typedef struct _OstreeRepoFileClass OstreeRepoFileClass;
-
-struct _OstreeRepoFileClass
-{
- GObjectClass parent_class;
-};
-
-GType _ostree_repo_file_get_type (void) G_GNUC_CONST;
-
-GFile * _ostree_repo_file_new_root (OstreeRepo *repo,
- const char *commit);
-
-OstreeRepoFile * _ostree_repo_file_new_empty_tree (OstreeRepo *repo);
-
-GFile * _ostree_repo_file_new_child (OstreeRepoFile *parent,
- const char *name);
-
-gboolean _ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
- GError **error);
-
-gboolean _ostree_repo_file_get_xattrs (OstreeRepoFile *self,
- GVariant **out_xattrs,
- GCancellable *cancellable,
- GError **error);
-
-OstreeRepo * _ostree_repo_file_get_repo (OstreeRepoFile *self);
-OstreeRepoFile * _ostree_repo_file_get_root (OstreeRepoFile *self);
-
-void _ostree_repo_file_make_empty_tree (OstreeRepoFile *self);
-
-void _ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
- const char *checksum,
- GVariant *metadata);
-
-void _ostree_repo_file_tree_set_content_checksum (OstreeRepoFile *self,
- const char *checksum);
-const char *_ostree_repo_file_tree_get_content_checksum (OstreeRepoFile *self);
-
-gboolean _ostree_repo_file_is_tree (OstreeRepoFile *self);
-
-const char * _ostree_repo_file_nontree_get_checksum (OstreeRepoFile *self);
-
-GFile *_ostree_repo_file_nontree_get_local (OstreeRepoFile *self);
-
-void _ostree_repo_file_tree_remove_child (OstreeRepoFile *self,
- const char *name);
-
-void _ostree_repo_file_tree_add_file (OstreeRepoFile *self,
- const char *name,
- const char *checksum);
-
-void _ostree_repo_file_tree_add_dir (OstreeRepoFile *self,
- const char *name,
- const char *content_checksum,
- const char *metadata_checksum);
-
-int _ostree_repo_file_tree_find_child (OstreeRepoFile *self,
- const char *name,
- gboolean *is_dir,
- GVariant **out_container);
-
-const char *_ostree_repo_file_tree_get_child_checksum (OstreeRepoFile *self,
- int n);
-
-gboolean _ostree_repo_file_tree_query_child (OstreeRepoFile *self,
- int n,
- const char *attributes,
- GFileQueryInfoFlags flags,
- GFileInfo **out_info,
- GCancellable *cancellable,
- GError **error);
-
-GVariant *_ostree_repo_file_tree_get_contents (OstreeRepoFile *self);
-GVariant *_ostree_repo_file_tree_get_metadata (OstreeRepoFile *self);
-
-G_END_DECLS
-
-#endif
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#define _GNU_SOURCE
-
-#include "config.h"
-
-#include "ostree.h"
-#include "otutil.h"
-#include "ostree-repo-file-enumerator.h"
-
-#include <gio/gunixoutputstream.h>
-#include <gio/gunixinputstream.h>
-
-enum {
- PROP_0,
-
- PROP_PATH
-};
-
-G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT)
-
-#define GET_PRIVATE(o) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((o), OSTREE_TYPE_REPO, OstreeRepoPrivate))
-
-typedef struct _OstreeRepoPrivate OstreeRepoPrivate;
-
-struct _OstreeRepoPrivate {
- char *path;
- GFile *repo_file;
- GFile *tmp_dir;
- GFile *local_heads_dir;
- GFile *remote_heads_dir;
- char *objects_path;
- char *config_path;
-
- gboolean inited;
-
- GKeyFile *config;
- gboolean archive;
-};
-
-static void
-ostree_repo_finalize (GObject *object)
-{
- OstreeRepo *self = OSTREE_REPO (object);
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
-
- g_free (priv->path);
- g_clear_object (&priv->repo_file);
- g_clear_object (&priv->tmp_dir);
- g_clear_object (&priv->local_heads_dir);
- g_clear_object (&priv->remote_heads_dir);
- g_free (priv->objects_path);
- g_free (priv->config_path);
- if (priv->config)
- g_key_file_free (priv->config);
-
- G_OBJECT_CLASS (ostree_repo_parent_class)->finalize (object);
-}
-
-static void
-ostree_repo_set_property(GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- OstreeRepo *self = OSTREE_REPO (object);
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
-
- switch (prop_id)
- {
- case PROP_PATH:
- priv->path = g_value_dup_string (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-ostree_repo_get_property(GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- OstreeRepo *self = OSTREE_REPO (object);
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
-
- switch (prop_id)
- {
- case PROP_PATH:
- g_value_set_string (value, priv->path);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GObject *
-ostree_repo_constructor (GType gtype,
- guint n_properties,
- GObjectConstructParam *properties)
-{
- GObject *object;
- GObjectClass *parent_class;
- OstreeRepoPrivate *priv;
-
- parent_class = G_OBJECT_CLASS (ostree_repo_parent_class);
- object = parent_class->constructor (gtype, n_properties, properties);
-
- priv = GET_PRIVATE (object);
-
- g_assert (priv->path != NULL);
-
- priv->repo_file = ot_util_new_file_for_path (priv->path);
- priv->tmp_dir = g_file_resolve_relative_path (priv->repo_file, "tmp");
- priv->local_heads_dir = g_file_resolve_relative_path (priv->repo_file, "refs/heads");
- priv->remote_heads_dir = g_file_resolve_relative_path (priv->repo_file, "refs/remotes");
-
- priv->objects_path = g_build_filename (priv->path, "objects", NULL);
- priv->config_path = g_build_filename (priv->path, "config", NULL);
-
- return object;
-}
-
-static void
-ostree_repo_class_init (OstreeRepoClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (OstreeRepoPrivate));
-
- object_class->constructor = ostree_repo_constructor;
- object_class->get_property = ostree_repo_get_property;
- object_class->set_property = ostree_repo_set_property;
- object_class->finalize = ostree_repo_finalize;
-
- g_object_class_install_property (object_class,
- PROP_PATH,
- g_param_spec_string ("path",
- "",
- "",
- NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-}
-
-static void
-ostree_repo_init (OstreeRepo *self)
-{
-}
-
-OstreeRepo*
-ostree_repo_new (const char *path)
-{
- return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
-}
-
-static gboolean
-parse_rev_file (OstreeRepo *self,
- const char *path,
- char **sha256,
- GError **error) G_GNUC_UNUSED;
-
-static gboolean
-parse_rev_file (OstreeRepo *self,
- const char *path,
- char **sha256,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- GError *temp_error = NULL;
- gboolean ret = FALSE;
- char *rev = NULL;
-
- rev = ot_util_get_file_contents_utf8 (path, &temp_error);
- if (rev == NULL)
- {
- if (g_error_matches (temp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
- {
- g_clear_error (&temp_error);
- }
- else
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- }
- else
- {
- g_strchomp (rev);
- }
-
- if (g_str_has_prefix (rev, "ref: "))
- {
- GFile *ref;
- char *ref_path;
- char *ref_sha256;
- gboolean subret;
-
- ref = g_file_resolve_relative_path (priv->local_heads_dir, rev + 5);
- ref_path = g_file_get_path (ref);
-
- subret = parse_rev_file (self, ref_path, &ref_sha256, error);
- g_clear_object (&ref);
- g_free (ref_path);
-
- if (!subret)
- {
- g_free (ref_sha256);
- goto out;
- }
-
- g_free (rev);
- rev = ref_sha256;
- }
- else
- {
- if (!ostree_validate_checksum_string (rev, error))
- goto out;
- }
-
- *sha256 = rev;
- rev = NULL;
- ret = TRUE;
- out:
- g_free (rev);
- return ret;
-}
-
-static gboolean
-resolve_rev (OstreeRepo *self,
- const char *rev,
- gboolean allow_noent,
- char **sha256,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- char *tmp = NULL;
- char *tmp2 = NULL;
- char *ret_rev = NULL;
- GFile *child = NULL;
- char *child_path = NULL;
- GError *temp_error = NULL;
- GVariant *commit = NULL;
-
- if (strlen (rev) == 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid empty rev");
- goto out;
- }
- else if (strlen (rev) == 64)
- {
- ret_rev = g_strdup (rev);
- }
- else if (g_str_has_suffix (rev, "^"))
- {
- tmp = g_strdup (rev);
- tmp[strlen(tmp) - 1] = '\0';
-
- if (!resolve_rev (self, tmp, allow_noent, &tmp2, error))
- goto out;
-
- if (!ostree_repo_load_variant_checked (self, OSTREE_SERIALIZED_COMMIT_VARIANT, tmp2, &commit, error))
- goto out;
-
- g_variant_get_child (commit, 2, "s", &ret_rev);
- if (strlen (ret_rev) == 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Commit %s has no parent", tmp2);
- goto out;
-
- }
- }
- else
- {
- child = g_file_get_child (priv->local_heads_dir, rev);
- child_path = g_file_get_path (child);
- if (!ot_util_gfile_load_contents_utf8 (child, NULL, &ret_rev, NULL, &temp_error))
- {
- if (allow_noent && g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
- {
- g_free (ret_rev);
- ret_rev = NULL;
- }
- else
- {
- g_propagate_error (error, temp_error);
- g_prefix_error (error, "Couldn't open ref '%s': ", child_path);
- goto out;
- }
- }
- else
- {
- g_strchomp (ret_rev);
-
- if (!ostree_validate_checksum_string (ret_rev, error))
- goto out;
- }
- }
-
- *sha256 = ret_rev;
- ret_rev = NULL;
- ret = TRUE;
- out:
- if (commit)
- g_variant_unref (commit);
- g_free (tmp);
- g_free (tmp2);
- g_clear_object (&child);
- g_free (child_path);
- g_free (ret_rev);
- return ret;
-}
-
-gboolean
-ostree_repo_resolve_rev (OstreeRepo *self,
- const char *rev,
- char **sha256,
- GError **error)
-{
- g_return_val_if_fail (rev != NULL, FALSE);
- return resolve_rev (self, rev, FALSE, sha256, error);
-}
-
-static gboolean
-write_checksum_file (GFile *parentdir,
- const char *name,
- const char *sha256,
- GError **error)
-{
- gboolean ret = FALSE;
- GFile *child = NULL;
- GOutputStream *out = NULL;
- gsize bytes_written;
-
- child = g_file_get_child (parentdir, name);
-
- if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, NULL, error)) == NULL)
- goto out;
- if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, NULL, error))
- goto out;
- if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, NULL, error))
- goto out;
- if (!g_output_stream_close (out, NULL, error))
- goto out;
-
- ret = TRUE;
- out:
- g_clear_object (&child);
- g_clear_object (&out);
- return ret;
-}
-
-/**
- * ostree_repo_get_config:
- * @self:
- *
- * Returns: (transfer none): The repository configuration; do not modify
- */
-GKeyFile *
-ostree_repo_get_config (OstreeRepo *self)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
-
- g_return_val_if_fail (priv->inited, NULL);
-
- return priv->config;
-}
-
-/**
- * ostree_repo_copy_config:
- * @self:
- *
- * Returns: (transfer full): A newly-allocated copy of the repository config
- */
-GKeyFile *
-ostree_repo_copy_config (OstreeRepo *self)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- GKeyFile *copy;
- char *data;
- gsize len;
-
- g_return_val_if_fail (priv->inited, NULL);
-
- copy = g_key_file_new ();
- data = g_key_file_to_data (priv->config, &len, NULL);
- if (!g_key_file_load_from_data (copy, data, len, 0, NULL))
- g_assert_not_reached ();
- g_free (data);
- return copy;
-}
-
-/**
- * ostree_repo_write_config:
- * @self:
- * @new_config: Overwrite the config file with this data. Do not change later!
- * @error: a #GError
- *
- * Save @new_config in place of this repository's config file. Note
- * that @new_config should not be modified after - this function
- * simply adds a reference.
- */
-gboolean
-ostree_repo_write_config (OstreeRepo *self,
- GKeyFile *new_config,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- char *data = NULL;
- gsize len;
- gboolean ret = FALSE;
-
- g_return_val_if_fail (priv->inited, FALSE);
-
- data = g_key_file_to_data (new_config, &len, error);
- if (!g_file_set_contents (priv->config_path, data, len, error))
- goto out;
-
- g_key_file_free (priv->config);
- priv->config = g_key_file_new ();
- if (!g_key_file_load_from_data (priv->config, data, len, 0, error))
- goto out;
-
- ret = TRUE;
- out:
- g_free (data);
- return ret;
-}
-
-gboolean
-ostree_repo_check (OstreeRepo *self, GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- char *version = NULL;;
- GError *temp_error = NULL;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- if (priv->inited)
- return TRUE;
-
- if (!g_file_test (priv->objects_path, G_FILE_TEST_IS_DIR))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Couldn't find objects directory '%s'", priv->objects_path);
- goto out;
- }
-
- priv->config = g_key_file_new ();
- if (!g_key_file_load_from_file (priv->config, priv->config_path, 0, error))
- {
- g_prefix_error (error, "Couldn't parse config file: ");
- goto out;
- }
-
- version = g_key_file_get_value (priv->config, "core", "repo_version", &temp_error);
- if (temp_error)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
-
- if (strcmp (version, "0") != 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid repository version '%s'", version);
- goto out;
- }
-
- priv->archive = g_key_file_get_boolean (priv->config, "core", "archive", &temp_error);
- if (temp_error)
- {
- if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND))
- {
- g_clear_error (&temp_error);
- }
- else
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- }
-
- priv->inited = TRUE;
-
- ret = TRUE;
- out:
- g_free (version);
- return ret;
-}
-
-const char *
-ostree_repo_get_path (OstreeRepo *self)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- return priv->path;
-}
-
-gboolean
-ostree_repo_is_archive (OstreeRepo *self)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
-
- g_return_val_if_fail (priv->inited, FALSE);
-
- return priv->archive;
-}
-
-static gboolean
-write_gvariant_to_tmp (OstreeRepo *self,
- OstreeSerializedVariantType type,
- GVariant *variant,
- GChecksum **out_checksum,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- GVariant *serialized = NULL;
- gboolean ret = FALSE;
- gsize bytes_written;
- char *tmp_name = NULL;
- char *dest_name = NULL;
- int fd = -1;
- GUnixOutputStream *stream = NULL;
- GChecksum *checksum = NULL;
-
- serialized = g_variant_new ("(uv)", GUINT32_TO_BE ((guint32)type), variant);
-
- tmp_name = g_build_filename (ot_gfile_get_path_cached (priv->tmp_dir), "variant-tmp-XXXXXX", NULL);
- fd = g_mkstemp (tmp_name);
- if (fd < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- checksum = g_checksum_new (G_CHECKSUM_SHA256);
-
- stream = (GUnixOutputStream*)g_unix_output_stream_new (fd, FALSE);
- if (!g_output_stream_write_all ((GOutputStream*)stream,
- g_variant_get_data (serialized),
- g_variant_get_size (serialized),
- &bytes_written,
- NULL,
- error))
- goto out;
-
- g_checksum_update (checksum, (guint8*)g_variant_get_data (serialized), g_variant_get_size (serialized));
-
- if (!g_output_stream_close ((GOutputStream*)stream,
- NULL, error))
- goto out;
-
- dest_name = g_build_filename (ot_gfile_get_path_cached (priv->tmp_dir), g_checksum_get_string (checksum), NULL);
- if (rename (tmp_name, dest_name) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- ret = TRUE;
- *out_checksum = checksum;
- checksum = NULL;
- out:
- /* Unconditionally unlink; if we suceeded, there's a new link, if not, clean up. */
- (void) unlink (tmp_name);
- if (fd != -1)
- close (fd);
- if (checksum)
- g_checksum_free (checksum);
- if (serialized != NULL)
- g_variant_unref (serialized);
- g_free (tmp_name);
- g_free (dest_name);
- g_clear_object (&stream);
- return ret;
-}
-
-static gboolean
-import_gvariant_object (OstreeRepo *self,
- OstreeSerializedVariantType type,
- GVariant *variant,
- GChecksum **out_checksum,
- GError **error)
-{
- gboolean ret = FALSE;
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- char *tmp_name = NULL;
- GChecksum *ret_checksum = NULL;
- gboolean did_exist;
-
- if (!write_gvariant_to_tmp (self, type, variant, &ret_checksum, error))
- goto out;
-
- tmp_name = g_build_filename (ot_gfile_get_path_cached (priv->tmp_dir),
- g_checksum_get_string (ret_checksum), NULL);
-
- if (!ostree_repo_store_object_trusted (self, tmp_name,
- g_checksum_get_string (ret_checksum),
- OSTREE_OBJECT_TYPE_META,
- TRUE, FALSE, &did_exist, error))
- goto out;
-
- ret = TRUE;
- *out_checksum = ret_checksum;
- ret_checksum = NULL;
- out:
- (void) unlink (tmp_name);
- g_free (tmp_name);
- if (ret_checksum)
- g_checksum_free (ret_checksum);
- return ret;
-}
-
-gboolean
-ostree_repo_load_variant_checked (OstreeRepo *self,
- OstreeSerializedVariantType expected_type,
- const char *sha256,
- GVariant **out_variant,
- GError **error)
-{
- gboolean ret = FALSE;
- OstreeSerializedVariantType type;
- GVariant *ret_variant = NULL;
-
- if (!ostree_repo_load_variant (self, sha256, &type, &ret_variant, error))
- goto out;
-
- if (type != expected_type)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted metadata object '%s'; found type %u, expected %u", sha256,
- type, (guint32)expected_type);
- goto out;
- }
-
- ret = TRUE;
- *out_variant = ret_variant;
- ret_variant = NULL;
- out:
- if (ret_variant)
- g_variant_unref (ret_variant);
- return ret;
-}
-
-static gboolean
-import_directory_meta (OstreeRepo *self,
- const char *path,
- GVariant **out_variant,
- GChecksum **out_checksum,
- GError **error)
-{
- gboolean ret = FALSE;
- struct stat stbuf;
- GChecksum *ret_checksum = NULL;
- GVariant *dirmeta = NULL;
- GVariant *xattrs = NULL;
-
- if (lstat (path, &stbuf) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- if (!S_ISDIR(stbuf.st_mode))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Not a directory: '%s'", path);
- goto out;
- }
-
- xattrs = ostree_get_xattrs_for_path (path, error);
- if (!xattrs)
- goto out;
-
- dirmeta = g_variant_new ("(uuuu@a(ayay))",
- OSTREE_DIR_META_VERSION,
- GUINT32_TO_BE ((guint32)stbuf.st_uid),
- GUINT32_TO_BE ((guint32)stbuf.st_gid),
- GUINT32_TO_BE ((guint32)stbuf.st_mode),
- xattrs);
- g_variant_ref_sink (dirmeta);
-
- if (!import_gvariant_object (self, OSTREE_SERIALIZED_DIRMETA_VARIANT,
- dirmeta, &ret_checksum, error))
- goto out;
-
- ret = TRUE;
- out:
- if (!ret)
- {
- if (ret_checksum)
- g_checksum_free (ret_checksum);
- if (dirmeta != NULL)
- g_variant_unref (dirmeta);
- }
- else
- {
- *out_checksum = ret_checksum;
- *out_variant = dirmeta;
- }
- if (xattrs)
- g_variant_unref (xattrs);
- return ret;
-}
-
-char *
-ostree_repo_get_object_path (OstreeRepo *self,
- const char *checksum,
- OstreeObjectType type)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- char *ret;
- char *relpath;
-
- relpath = ostree_get_relative_object_path (checksum, type, priv->archive);
- ret = g_build_filename (priv->path, relpath, NULL);
- g_free (relpath);
-
- return ret;
-}
-
-static char *
-prepare_dir_for_checksum_get_object_path (OstreeRepo *self,
- const char *checksum,
- OstreeObjectType type,
- GError **error)
-{
- char *checksum_dir = NULL;
- char *object_path = NULL;
-
- object_path = ostree_repo_get_object_path (self, checksum, type);
- checksum_dir = g_path_get_dirname (object_path);
-
- if (!ot_util_ensure_directory (checksum_dir, FALSE, error))
- goto out;
-
- out:
- g_free (checksum_dir);
- return object_path;
-}
-
-static gboolean
-link_object_trusted (OstreeRepo *self,
- const char *path,
- const char *checksum,
- OstreeObjectType objtype,
- gboolean ignore_exists,
- gboolean force,
- gboolean *did_exist,
- GError **error)
-{
- char *src_basename = NULL;
- char *src_dirname = NULL;
- char *dest_basename = NULL;
- char *tmp_dest_basename = NULL;
- char *dest_dirname = NULL;
- DIR *src_dir = NULL;
- DIR *dest_dir = NULL;
- gboolean ret = FALSE;
- char *dest_path = NULL;
-
- src_basename = g_path_get_basename (path);
- src_dirname = g_path_get_dirname (path);
-
- src_dir = opendir (src_dirname);
- if (src_dir == NULL)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- dest_path = prepare_dir_for_checksum_get_object_path (self, checksum, objtype, error);
- if (!dest_path)
- goto out;
-
- dest_basename = g_path_get_basename (dest_path);
- dest_dirname = g_path_get_dirname (dest_path);
- dest_dir = opendir (dest_dirname);
- if (dest_dir == NULL)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- if (force)
- {
- tmp_dest_basename = g_strconcat (dest_basename, ".tmp", NULL);
- (void) unlinkat (dirfd (dest_dir), tmp_dest_basename, 0);
- }
- else
- tmp_dest_basename = g_strdup (dest_basename);
-
- if (linkat (dirfd (src_dir), src_basename, dirfd (dest_dir), tmp_dest_basename, 0) < 0)
- {
- if (errno != EEXIST || !ignore_exists)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- else
- *did_exist = TRUE;
- }
- else
- *did_exist = FALSE;
-
- if (force)
- {
- if (renameat (dirfd (dest_dir), tmp_dest_basename,
- dirfd (dest_dir), dest_basename) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- (void) unlinkat (dirfd (dest_dir), tmp_dest_basename, 0);
- }
-
- ret = TRUE;
- out:
- if (src_dir != NULL)
- closedir (src_dir);
- if (dest_dir != NULL)
- closedir (dest_dir);
- g_free (src_basename);
- g_free (src_dirname);
- g_free (dest_basename);
- g_free (tmp_dest_basename);
- g_free (dest_dirname);
- g_free (dest_path);
- return ret;
-}
-
-static gboolean
-archive_file_trusted (OstreeRepo *self,
- const char *path,
- const char *checksum,
- OstreeObjectType objtype,
- gboolean ignore_exists,
- gboolean force,
- gboolean *did_exist,
- GError **error)
-{
- GFile *infile = NULL;
- GFile *outfile = NULL;
- GFileOutputStream *out = NULL;
- gboolean ret = FALSE;
- char *dest_path = NULL;
- char *dest_tmp_path = NULL;
-
- infile = ot_util_new_file_for_path (path);
-
- dest_path = prepare_dir_for_checksum_get_object_path (self, checksum, objtype, error);
- if (!dest_path)
- goto out;
-
- dest_tmp_path = g_strconcat (dest_path, ".tmp", NULL);
-
- outfile = ot_util_new_file_for_path (dest_tmp_path);
- out = g_file_replace (outfile, NULL, FALSE, 0, NULL, error);
- if (!out)
- goto out;
-
- if (!ostree_pack_object ((GOutputStream*)out, infile, objtype, NULL, error))
- goto out;
-
- if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
- goto out;
-
- if (rename (dest_tmp_path, dest_path) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
-
- ret = TRUE;
- out:
- g_free (dest_path);
- g_free (dest_tmp_path);
- g_clear_object (&infile);
- g_clear_object (&outfile);
- g_clear_object (&out);
- return ret;
-}
-
-gboolean
-ostree_repo_store_object_trusted (OstreeRepo *self,
- const char *path,
- const char *checksum,
- OstreeObjectType objtype,
- gboolean ignore_exists,
- gboolean force,
- gboolean *did_exist,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- if (priv->archive && objtype == OSTREE_OBJECT_TYPE_FILE)
- return archive_file_trusted (self, path, checksum, objtype, ignore_exists, force, did_exist, error);
- else
- return link_object_trusted (self, path, checksum, objtype, ignore_exists, force, did_exist, error);
-}
-
-gboolean
-ostree_repo_store_packfile (OstreeRepo *self,
- const char *expected_checksum,
- const char *path,
- OstreeObjectType objtype,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- GString *tempfile_path = NULL;
- GChecksum *checksum = NULL;
- gboolean did_exist;
-
- tempfile_path = g_string_new (priv->path);
- g_string_append_printf (tempfile_path, "/tmp-unpack-%s", expected_checksum);
-
- if (!ostree_unpack_object (path, objtype, tempfile_path->str, &checksum, error))
- goto out;
-
- if (strcmp (g_checksum_get_string (checksum), expected_checksum) != 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Corrupted object %s (actual checksum is %s)",
- expected_checksum, g_checksum_get_string (checksum));
- goto out;
- }
-
- if (!ostree_repo_store_object_trusted (self, tempfile_path ? tempfile_path->str : path,
- expected_checksum,
- objtype,
- TRUE, FALSE, &did_exist, error))
- goto out;
-
- ret = TRUE;
- out:
- if (tempfile_path)
- {
- (void) unlink (tempfile_path->str);
- g_string_free (tempfile_path, TRUE);
- }
- if (checksum)
- g_checksum_free (checksum);
- return ret;
-}
-
-typedef struct _ParsedTreeData ParsedTreeData;
-typedef struct _ParsedDirectoryData ParsedDirectoryData;
-
-static void parsed_tree_data_free (ParsedTreeData *pdata);
-
-struct _ParsedDirectoryData {
- ParsedTreeData *tree_data;
- char *metadata_sha256;
- GVariant *meta_data;
-};
-
-static void
-parsed_directory_data_free (ParsedDirectoryData *pdata)
-{
- if (pdata == NULL)
- return;
- parsed_tree_data_free (pdata->tree_data);
- g_free (pdata->metadata_sha256);
- g_variant_unref (pdata->meta_data);
- g_free (pdata);
-}
-
-struct _ParsedTreeData {
- GHashTable *files; /* char* filename -> char* checksum */
- GHashTable *directories; /* char* dirname -> ParsedDirectoryData* */
-};
-
-static ParsedTreeData *
-parsed_tree_data_new (void)
-{
- ParsedTreeData *ret = g_new0 (ParsedTreeData, 1);
- ret->files = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)g_free);
- ret->directories = g_hash_table_new_full (g_str_hash, g_str_equal,
- (GDestroyNotify)g_free,
- (GDestroyNotify)parsed_directory_data_free);
- return ret;
-}
-
-static void
-parsed_tree_data_free (ParsedTreeData *pdata)
-{
- if (pdata == NULL)
- return;
- g_hash_table_destroy (pdata->files);
- g_hash_table_destroy (pdata->directories);
- g_free (pdata);
-}
-
-static GVariant *
-create_empty_gvariant_dict (void)
-{
- GVariantBuilder builder;
- g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sv}"));
- return g_variant_builder_end (&builder);
-}
-
-static gboolean
-import_parsed_tree (OstreeRepo *self,
- ParsedTreeData *tree,
- GChecksum **out_checksum,
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *serialized_tree = NULL;
- gboolean builders_initialized = FALSE;
- GVariantBuilder files_builder;
- GVariantBuilder dirs_builder;
- GHashTableIter hash_iter;
- GSList *sorted_filenames = NULL;
- GSList *iter;
- gpointer key, value;
-
- g_variant_builder_init (&files_builder, G_VARIANT_TYPE ("a(ss)"));
- g_variant_builder_init (&dirs_builder, G_VARIANT_TYPE ("a(sss)"));
- builders_initialized = TRUE;
-
- g_hash_table_iter_init (&hash_iter, tree->files);
- while (g_hash_table_iter_next (&hash_iter, &key, &value))
- {
- const char *name = key;
- sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
- }
-
- sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
-
- for (iter = sorted_filenames; iter; iter = iter->next)
- {
- const char *name = iter->data;
- const char *value;
-
- value = g_hash_table_lookup (tree->files, name);
- g_variant_builder_add (&files_builder, "(ss)", name, value);
- }
-
- g_slist_free (sorted_filenames);
- sorted_filenames = NULL;
-
- g_hash_table_iter_init (&hash_iter, tree->directories);
- while (g_hash_table_iter_next (&hash_iter, &key, &value))
- {
- const char *name = key;
- sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
- }
-
- sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
-
- for (iter = sorted_filenames; iter; iter = iter->next)
- {
- const char *name = iter->data;
- GChecksum *dir_checksum = NULL;
- ParsedDirectoryData *dir;
-
- dir = g_hash_table_lookup (tree->directories, name);
-
- if (!import_parsed_tree (self, dir->tree_data, &dir_checksum, error))
- goto out;
-
- g_variant_builder_add (&dirs_builder, "(sss)",
- name, g_checksum_get_string (dir_checksum), dir->metadata_sha256);
- g_checksum_free (dir_checksum);
- }
-
- g_slist_free (sorted_filenames);
- sorted_filenames = NULL;
-
- serialized_tree = g_variant_new ("(u@a{sv}@a(ss)@a(sss))",
- GUINT32_TO_BE (0),
- create_empty_gvariant_dict (),
- g_variant_builder_end (&files_builder),
- g_variant_builder_end (&dirs_builder));
- builders_initialized = FALSE;
- g_variant_ref_sink (serialized_tree);
- if (!import_gvariant_object (self, OSTREE_SERIALIZED_TREE_VARIANT, serialized_tree, out_checksum, error))
- goto out;
-
- ret = TRUE;
- out:
- g_slist_free (sorted_filenames);
- if (builders_initialized)
- {
- g_variant_builder_clear (&files_builder);
- g_variant_builder_clear (&dirs_builder);
- }
- if (serialized_tree)
- g_variant_unref (serialized_tree);
- return ret;
-}
-
-static gboolean
-check_path (const char *filename,
- GError **error)
-{
- gboolean ret = FALSE;
-
- if (!*filename)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid empty filename");
- goto out;
- }
-
- if (strcmp (filename, ".") == 0)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Self-reference '.' in filename '%s' not allowed (yet)", filename);
- goto out;
- }
-
- if (ot_util_filename_has_dotdot (filename))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Path uplink '..' in filename '%s' not allowed (yet)", filename);
- goto out;
- }
-
- if (g_path_is_absolute (filename))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Absolute filename '%s' not allowed (yet)", filename);
- goto out;
- }
-
- ret = TRUE;
- out:
- return ret;
-}
-
-static gboolean
-add_one_directory_to_tree_and_import (OstreeRepo *self,
- const char *basename,
- const char *abspath,
- ParsedTreeData *tree,
- ParsedDirectoryData **dir, /*inout*/
- GError **error)
-{
- gboolean ret = FALSE;
- GVariant *dirmeta = NULL;
- GChecksum *dir_meta_checksum = NULL;
- ParsedDirectoryData *dir_value = *dir;
-
- g_assert (tree != NULL);
-
- if (!import_directory_meta (self, abspath, &dirmeta, &dir_meta_checksum, error))
- goto out;
-
- if (dir_value)
- {
- g_variant_unref (dir_value->meta_data);
- dir_value->meta_data = dirmeta;
- }
- else
- {
- dir_value = g_new0 (ParsedDirectoryData, 1);
- dir_value->tree_data = parsed_tree_data_new ();
- dir_value->metadata_sha256 = g_strdup (g_checksum_get_string (dir_meta_checksum));
- dir_value->meta_data = dirmeta;
- g_hash_table_insert (tree->directories, g_strdup (basename), dir_value);
- }
-
- ret = TRUE;
- *dir = dir_value;
- out:
- if (dir_meta_checksum)
- g_checksum_free (dir_meta_checksum);
- return ret;
-}
-
-static gboolean
-add_one_file_to_tree_and_import (OstreeRepo *self,
- const char *basename,
- const char *abspath,
- ParsedTreeData *tree,
- GError **error)
-{
- gboolean ret = FALSE;
- GChecksum *checksum = NULL;
- struct stat stbuf;
- gboolean did_exist;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_assert (tree != NULL);
-
- if (!ostree_stat_and_checksum_file (-1, abspath, OSTREE_OBJECT_TYPE_FILE, &checksum, &stbuf, error))
- goto out;
-
- if (!ostree_repo_store_object_trusted (self, abspath, g_checksum_get_string (checksum),
- OSTREE_OBJECT_TYPE_FILE, TRUE, FALSE, &did_exist, error))
- goto out;
-
- g_hash_table_replace (tree->files, g_strdup (basename),
- g_strdup (g_checksum_get_string (checksum)));
-
- ret = TRUE;
- out:
- if (checksum)
- g_checksum_free (checksum);
- return ret;
-}
-
-static gboolean
-add_one_path_to_tree_and_import (OstreeRepo *self,
- const char *base,
- const char *filename,
- ParsedTreeData *tree,
- GError **error)
-{
- gboolean ret = FALSE;
- GPtrArray *components = NULL;
- struct stat stbuf;
- char *component_abspath = NULL;
- ParsedTreeData *current_tree = tree;
- const char *component = NULL;
- const char *file_sha1;
- char *abspath = NULL;
- ParsedDirectoryData *dir;
- int i;
- gboolean is_directory;
-
- if (!check_path (filename, error))
- goto out;
-
- abspath = g_build_filename (base, filename, NULL);
-
- if (lstat (abspath, &stbuf) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- is_directory = S_ISDIR(stbuf.st_mode);
-
- if (components)
- g_ptr_array_free (components, TRUE);
- components = ot_util_path_split (filename);
- g_assert (components->len > 0);
-
- current_tree = tree;
- for (i = 0; i < components->len; i++)
- {
- component = components->pdata[i];
- g_free (component_abspath);
- component_abspath = ot_util_path_join_n (base, components, i);
- file_sha1 = g_hash_table_lookup (current_tree->files, component);
- dir = g_hash_table_lookup (current_tree->directories, component);
-
- g_assert_cmpstr (component, !=, ".");
-
- if (i < components->len - 1)
- {
- if (file_sha1 != NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Encountered non-directory '%s' in '%s'",
- component,
- filename);
- goto out;
- }
- /* Implicitly add intermediate directories */
- if (!add_one_directory_to_tree_and_import (self, component,
- component_abspath, current_tree, &dir,
- error))
- goto out;
- g_assert (dir != NULL);
- current_tree = dir->tree_data;
- }
- else if (is_directory)
- {
- if (file_sha1 != NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "File '%s' can't be overwritten by directory",
- filename);
- goto out;
- }
- if (!add_one_directory_to_tree_and_import (self, component,
- abspath, current_tree, &dir,
- error))
- goto out;
- }
- else
- {
- g_assert (!is_directory);
- if (dir != NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "File '%s' can't be overwritten by directory",
- filename);
- goto out;
- }
- if (!add_one_file_to_tree_and_import (self, component, abspath,
- current_tree, error))
- goto out;
- }
- }
-
- ret = TRUE;
- out:
- if (components)
- g_ptr_array_unref (components);
- g_free (component_abspath);
- g_free (abspath);
- return ret;
-}
-
-gboolean
-ostree_repo_write_ref (OstreeRepo *self,
- gboolean is_local,
- const char *name,
- const char *rev,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- return write_checksum_file (is_local ? priv->local_heads_dir : priv->remote_heads_dir,
- name, rev, error);
-}
-
-static gboolean
-commit_parsed_tree (OstreeRepo *self,
- const char *branch,
- const char *parent,
- const char *subject,
- const char *body,
- GVariant *metadata,
- ParsedDirectoryData *root,
- GChecksum **out_commit,
- GError **error)
-{
- gboolean ret = FALSE;
- GChecksum *root_checksum = NULL;
- GChecksum *ret_commit = NULL;
- GVariant *commit = NULL;
- GDateTime *now = NULL;
-
- g_assert (branch != NULL);
- g_assert (subject != NULL);
-
- if (!import_parsed_tree (self, root->tree_data, &root_checksum, error))
- goto out;
-
- now = g_date_time_new_now_utc ();
- commit = g_variant_new ("(u@a{sv}ssstss)",
- GUINT32_TO_BE (OSTREE_COMMIT_VERSION),
- metadata ? metadata : create_empty_gvariant_dict (),
- parent ? parent : "",
- subject, body ? body : "",
- GUINT64_TO_BE (g_date_time_to_unix (now)),
- g_checksum_get_string (root_checksum),
- root->metadata_sha256);
- g_variant_ref_sink (commit);
- if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
- commit, &ret_commit, error))
- goto out;
-
- if (!ostree_repo_write_ref (self, TRUE, branch, g_checksum_get_string (ret_commit), error))
- goto out;
-
- ret = TRUE;
- *out_commit = ret_commit;
- out:
- if (root_checksum)
- g_checksum_free (root_checksum);
- if (commit)
- g_variant_unref (commit);
- if (now)
- g_date_time_unref (now);
- return ret;
-}
-
-static gboolean
-import_root (OstreeRepo *self,
- const char *base,
- ParsedDirectoryData **out_root,
- GError **error)
-{
- gboolean ret = FALSE;
- ParsedDirectoryData *ret_root = NULL;
- GVariant *root_metadata = NULL;
- GChecksum *root_meta_checksum = NULL;
-
- if (!import_directory_meta (self, base, &root_metadata, &root_meta_checksum, error))
- goto out;
-
- ret_root = g_new0 (ParsedDirectoryData, 1);
- ret_root->tree_data = parsed_tree_data_new ();
- ret_root->meta_data = root_metadata;
- root_metadata = NULL;
- ret_root->metadata_sha256 = g_strdup (g_checksum_get_string (root_meta_checksum));
-
- ret = TRUE;
- *out_root = ret_root;
- ret_root = NULL;
- out:
- if (root_metadata)
- g_variant_unref (root_metadata);
- if (root_meta_checksum)
- g_checksum_free (root_meta_checksum);
- parsed_directory_data_free (ret_root);
- return ret;
-}
-
-gboolean
-ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
- const char *branch,
- const char *parent,
- const char *subject,
- const char *body,
- GVariant *metadata,
- const char *base,
- int fd,
- char separator,
- GChecksum **out_commit,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- ParsedDirectoryData *root = NULL;
- GChecksum *ret_commit_checksum = NULL;
- GUnixInputStream *in = NULL;
- GDataInputStream *datain = NULL;
- char *filename = NULL;
- gsize filename_len;
- GError *temp_error = NULL;
- GVariant *root_metadata = NULL;
- GChecksum *root_meta_checksum = NULL;
- char *current_head = NULL;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (priv->inited, FALSE);
- g_return_val_if_fail (branch != NULL, FALSE);
- g_return_val_if_fail (subject != NULL, FALSE);
- g_return_val_if_fail (metadata == NULL || g_variant_is_of_type (metadata, G_VARIANT_TYPE ("a{sv}")), FALSE);
-
- if (parent == NULL)
- parent = branch;
-
- /* We're overwriting the tree */
- if (!import_root (self, base, &root, error))
- goto out;
-
- if (!resolve_rev (self, parent, TRUE, ¤t_head, error))
- goto out;
-
- in = (GUnixInputStream*)g_unix_input_stream_new (fd, FALSE);
- datain = g_data_input_stream_new ((GInputStream*)in);
-
- while ((filename = g_data_input_stream_read_upto (datain, &separator, 1,
- &filename_len, NULL, &temp_error)) != NULL)
- {
- if (!g_data_input_stream_read_byte (datain, NULL, &temp_error))
- {
- if (temp_error != NULL)
- {
- g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
- goto out;
- }
- }
- if (!add_one_path_to_tree_and_import (self, base, filename, root->tree_data, error))
- goto out;
- g_free (filename);
- filename = NULL;
- }
- if (filename == NULL && temp_error != NULL)
- {
- g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
- goto out;
- }
- if (!commit_parsed_tree (self, branch, current_head, subject, body, metadata,
- root, &ret_commit_checksum, error))
- goto out;
-
- ret = TRUE;
- *out_commit = ret_commit_checksum;
- ret_commit_checksum = NULL;
- out:
- if (ret_commit_checksum)
- g_checksum_free (ret_commit_checksum);
- g_free (current_head);
- if (root_metadata)
- g_variant_unref (root_metadata);
- if (root_meta_checksum)
- g_checksum_free (root_meta_checksum);
- g_clear_object (&datain);
- g_clear_object (&in);
- g_free (filename);
- parsed_directory_data_free (root);
- return ret;
-
-}
-
-static gboolean
-iter_object_dir (OstreeRepo *self,
- GFile *dir,
- OstreeRepoObjectIter callback,
- gpointer user_data,
- GError **error)
-{
- gboolean ret = FALSE;
- GError *temp_error = NULL;
- GFileEnumerator *enumerator = NULL;
- GFileInfo *file_info = NULL;
- char *dirpath = NULL;
-
- dirpath = g_file_get_path (dir);
-
- enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL,
- error);
- if (!enumerator)
- goto out;
-
- while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
- {
- const char *name;
- guint32 type;
- name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
- type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
-
- if (type != G_FILE_TYPE_DIRECTORY
- && (g_str_has_suffix (name, ".meta")
- || g_str_has_suffix (name, ".file")
- || g_str_has_suffix (name, ".packfile")))
- {
- char *dot;
- char *path;
-
- dot = strrchr (name, '.');
- g_assert (dot);
-
- if ((dot - name) == 62)
- {
- path = g_build_filename (dirpath, name, NULL);
- callback (self, path, file_info, user_data);
- g_free (path);
- }
- }
-
- g_object_unref (file_info);
- }
- if (file_info == NULL && temp_error != NULL)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- if (!g_file_enumerator_close (enumerator, NULL, error))
- goto out;
-
- ret = TRUE;
- out:
- g_free (dirpath);
- return ret;
-}
-
-gboolean
-ostree_repo_iter_objects (OstreeRepo *self,
- OstreeRepoObjectIter callback,
- gpointer user_data,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- GFile *objectdir = NULL;
- GFileEnumerator *enumerator = NULL;
- gboolean ret = FALSE;
- GFileInfo *file_info = NULL;
- GError *temp_error = NULL;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (priv->inited, FALSE);
-
- objectdir = ot_util_new_file_for_path (priv->objects_path);
- enumerator = g_file_enumerate_children (objectdir, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL,
- error);
- if (!enumerator)
- goto out;
-
- while ((file_info = g_file_enumerator_next_file (enumerator, NULL, &temp_error)) != NULL)
- {
- const char *name;
- guint32 type;
-
- name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
- type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
-
- if (strlen (name) == 2 && type == G_FILE_TYPE_DIRECTORY)
- {
- GFile *objdir = g_file_get_child (objectdir, name);
- if (!iter_object_dir (self, objdir, callback, user_data, error))
- {
- g_object_unref (objdir);
- goto out;
- }
- g_object_unref (objdir);
- }
- g_object_unref (file_info);
- }
- if (file_info == NULL && temp_error != NULL)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
- if (!g_file_enumerator_close (enumerator, NULL, error))
- goto out;
-
- ret = TRUE;
- out:
- g_clear_object (&file_info);
- g_clear_object (&enumerator);
- g_clear_object (&objectdir);
- return ret;
-}
-
-gboolean
-ostree_repo_load_variant (OstreeRepo *self,
- const char *sha256,
- OstreeSerializedVariantType *out_type,
- GVariant **out_variant,
- GError **error)
-{
- gboolean ret = FALSE;
- OstreeSerializedVariantType ret_type;
- GVariant *ret_variant = NULL;
- char *path = NULL;
-
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- path = ostree_repo_get_object_path (self, sha256, OSTREE_OBJECT_TYPE_META);
- if (!ostree_parse_metadata_file (path, &ret_type, &ret_variant, error))
- goto out;
-
- ret = TRUE;
- *out_type = ret_type;
- *out_variant = ret_variant;
- ret_variant = NULL;
- out:
- if (ret_variant)
- g_variant_unref (ret_variant);
- g_free (path);
- return ret;
-}
-
-static gboolean
-checkout_tree (OstreeRepo *self,
- OstreeRepoFile *dir,
- const char *destination,
- GCancellable *cancellable,
- GError **error);
-
-static gboolean
-checkout_one_directory (OstreeRepo *self,
- const char *destination,
- const char *dirname,
- OstreeRepoFile *dir,
- GFileInfo *dir_info,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- char *dest_path = NULL;
- GVariant *xattr_variant = NULL;
-
- dest_path = g_build_filename (destination, dirname, NULL);
-
- if (!_ostree_repo_file_get_xattrs (dir, &xattr_variant, NULL, error))
- goto out;
-
- if (mkdir (dest_path, (mode_t)g_file_info_get_attribute_uint32 (dir_info, "unix::mode")) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- g_prefix_error (error, "Failed to create directory '%s': ", dest_path);
- goto out;
- }
-
- if (!ostree_set_xattrs (dest_path, xattr_variant, cancellable, error))
- goto out;
-
- if (!checkout_tree (self, dir, dest_path, cancellable, error))
- goto out;
-
- ret = TRUE;
- out:
- g_free (dest_path);
- if (xattr_variant)
- g_variant_unref (xattr_variant);
- return ret;
-}
-
-static gboolean
-checkout_tree (OstreeRepo *self,
- OstreeRepoFile *dir,
- const char *destination,
- GCancellable *cancellable,
- GError **error)
-{
- OstreeRepoPrivate *priv = GET_PRIVATE (self);
- gboolean ret = FALSE;
- GError *temp_error = NULL;
- GFileInfo *file_info = NULL;
- GFileEnumerator *dir_enum = NULL;
- GFile *child = NULL;
- char *object_path = NULL;
- char *dest_path = NULL;
-
- dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- cancellable,
- error);
- if (!dir_enum)
- goto out;
-
- while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
- {
- const char *name;
- guint32 type;
-
- name = g_file_info_get_attribute_byte_string (file_info, "standard::name");
- type = g_file_info_get_attribute_uint32 (file_info, "standard::type");
-
- child = g_file_get_child ((GFile*)dir, name);
-
- if (type == G_FILE_TYPE_DIRECTORY)
- {
- if (!checkout_one_directory (self, destination, name, (OstreeRepoFile*)child, file_info, cancellable, error))
- goto out;
- }
- else
- {
- const char *checksum = _ostree_repo_file_nontree_get_checksum ((OstreeRepoFile*)child);
-
- dest_path = g_build_filename (destination, name, NULL);
- object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_FILE);
-
- if (priv->archive)
- {
- if (!ostree_unpack_object (object_path, OSTREE_OBJECT_TYPE_FILE, dest_path, NULL, error))
- goto out;
- }
- else
- {
- if (link (object_path, dest_path) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
- }
- }
-
- g_free (object_path);
- object_path = NULL;
- g_free (dest_path);
- dest_path = NULL;
- g_clear_object (&file_info);
- g_clear_object (&child);
- }
- if (file_info == NULL && temp_error != NULL)
- {
- g_propagate_error (error, temp_error);
- goto out;
- }
-
- ret = TRUE;
- out:
- g_clear_object (&dir_enum);
- g_clear_object (&file_info);
- g_clear_object (&child);
- g_free (object_path);
- g_free (dest_path);
- return ret;
-}
-
-gboolean
-ostree_repo_checkout (OstreeRepo *self,
- const char *rev,
- const char *destination,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- char *resolved = NULL;
- OstreeRepoFile *root = NULL;
- GFileInfo *root_info = NULL;
-
- if (g_file_test (destination, G_FILE_TEST_EXISTS))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Destination path '%s' already exists",
- destination);
- goto out;
- }
-
- if (!resolve_rev (self, rev, FALSE, &resolved, error))
- goto out;
-
- root = (OstreeRepoFile*)_ostree_repo_file_new_root (self, resolved);
- if (!_ostree_repo_file_ensure_resolved (root, error))
- goto out;
-
- root_info = g_file_query_info ((GFile*)root, OSTREE_GIO_FAST_QUERYINFO,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL, error);
- if (!root_info)
- goto out;
-
- if (!checkout_one_directory (self, destination, NULL, root, root_info, cancellable, error))
- goto out;
-
- ret = TRUE;
- out:
- g_free (resolved);
- g_clear_object (&root);
- g_clear_object (&root_info);
- return ret;
-}
-
-gboolean
-ostree_repo_diff (OstreeRepo *self,
- const char *ref,
- GFile *target,
- GPtrArray **out_modified,
- GPtrArray **out_removed,
- GPtrArray **out_added,
- GCancellable *cancellable,
- GError **error)
-{
- gboolean ret = FALSE;
- GPtrArray *ret_modified = NULL;
- GPtrArray *ret_removed = NULL;
- GPtrArray *ret_added = NULL;
-
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- "Not implemented yet");
- goto out;
-
- ret = TRUE;
- out:
- if (ret_modified)
- g_ptr_array_free (ret_modified, TRUE);
- if (ret_removed)
- g_ptr_array_free (ret_removed, TRUE);
- if (ret_added)
- g_ptr_array_free (ret_added, TRUE);
- return ret;
-}
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef _OSTREE_REPO
-#define _OSTREE_REPO
-
-#include "ostree-core.h"
-
-G_BEGIN_DECLS
-
-#define OSTREE_TYPE_REPO ostree_repo_get_type()
-#define OSTREE_REPO(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_REPO, OstreeRepo))
-#define OSTREE_REPO_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), OSTREE_TYPE_REPO, OstreeRepoClass))
-#define OSTREE_IS_REPO(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_REPO))
-#define OSTREE_IS_REPO_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), OSTREE_TYPE_REPO))
-#define OSTREE_REPO_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), OSTREE_TYPE_REPO, OstreeRepoClass))
-
-typedef struct {
- GObject parent;
-} OstreeRepo;
-
-typedef struct {
- GObjectClass parent_class;
-} OstreeRepoClass;
-
-GType ostree_repo_get_type (void);
-
-OstreeRepo* ostree_repo_new (const char *path);
-
-gboolean ostree_repo_check (OstreeRepo *self, GError **error);
-
-const char * ostree_repo_get_path (OstreeRepo *self);
-
-gboolean ostree_repo_is_archive (OstreeRepo *self);
-
-GKeyFile * ostree_repo_get_config (OstreeRepo *self);
-
-GKeyFile * ostree_repo_copy_config (OstreeRepo *self);
-
-gboolean ostree_repo_write_config (OstreeRepo *self,
- GKeyFile *new_config,
- GError **error);
-
-char * ostree_repo_get_object_path (OstreeRepo *self,
- const char *object,
- OstreeObjectType type);
-
-gboolean ostree_repo_store_packfile (OstreeRepo *self,
- const char *expected_checksum,
- const char *path,
- OstreeObjectType objtype,
- GError **error);
-
-gboolean ostree_repo_store_object_trusted (OstreeRepo *self,
- const char *path,
- const char *checksum,
- OstreeObjectType objtype,
- gboolean ignore_exists,
- gboolean force,
- gboolean *did_exist,
- GError **error);
-
-gboolean ostree_repo_resolve_rev (OstreeRepo *self,
- const char *rev,
- char **out_resolved,
- GError **error);
-
-gboolean ostree_repo_write_ref (OstreeRepo *self,
- gboolean is_local,
- const char *name,
- const char *rev,
- GError **error);
-
-gboolean ostree_repo_load_variant (OstreeRepo *self,
- const char *sha256,
- OstreeSerializedVariantType *out_type,
- GVariant **out_variant,
- GError **error);
-
-gboolean ostree_repo_load_variant_checked (OstreeRepo *self,
- OstreeSerializedVariantType expected_type,
- const char *sha256,
- GVariant **out_variant,
- GError **error);
-
-gboolean ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
- const char *branch,
- const char *parent,
- const char *subject,
- const char *body,
- GVariant *metadata,
- const char *base,
- int fd,
- char separator,
- GChecksum **out_commit,
- GError **error);
-
-gboolean ostree_repo_checkout (OstreeRepo *self,
- const char *ref,
- const char *destination,
- GCancellable *cancellable,
- GError **error);
-
-typedef struct {
- guint content_differs : 1;
- guint xattrs_differs : 1;
- guint unused : 30;
-
- GFileInfo *src_info;
- GFileInfo *target_info;
-
- char *src_file_checksum;
- char *target_file_checksum;
-
- GVariant *src_xattrs;
- GVariant *target_xattrs;
-} OstreeRepoDiffItem;
-
-gboolean ostree_repo_diff (OstreeRepo *self,
- const char *ref,
- GFile *target,
- GPtrArray **out_modified, /* OstreeRepoDiffItem */
- GPtrArray **out_removed, /* OstreeRepoDiffItem */
- GPtrArray **out_added, /* OstreeRepoDiffItem */
- GCancellable *cancellable,
- GError **error);
-
-typedef void (*OstreeRepoObjectIter) (OstreeRepo *self, const char *path,
- GFileInfo *fileinfo, gpointer user_data);
-
-gboolean ostree_repo_iter_objects (OstreeRepo *self,
- OstreeRepoObjectIter callback,
- gpointer user_data,
- GError **error);
-
-G_END_DECLS
-
-#endif /* _OSTREE_REPO */
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright (C) 2011 Colin Walters <walters@verbum.org>.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- * Author: Colin Walters <walters@verbum.org>
- */
-
-#ifndef __OSTREE_H__
-
-#include <ostree-core.h>
-#include <ostree-repo.h>
-#include <ostree-checkout.h>
-
-#endif